leetcode 刷题

[TOC]

9. 回文数

/*

给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false 。

回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。

例如,121 是回文,而 123 不是。


示例 1:

输入:x = 121
输出:true
示例 2:

输入:x = -121
输出:false
解释:从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。
示例 3:

输入:x = 10
输出:false
解释:从右向左读, 为 01 。因此它不是一个回文数。


提示:

-231 <= x <= 231 - 1

*/

思路

1.字符串翻转比较 strrev 函数或者自己写
2.字符串逐个前后比较
3.数字取模翻转比较
4.数字取模取一半,跟前半部分比较 ;分奇数偶数情况

代码

class Solution {

    /**
     * @param Integer $x
     * @return Boolean
     */
    function isPalindrome($x) {
        //方式1:翻转字符串 比较
        $x = (string) $x;
        $len = strlen($x);
        $str = '';
        for ($i=0; $i < $len; $i++) { 
            $str .= $x[$len-1-$i];
            # code...
        }

        if($str == $x){
            return true;
        }

        return false;
    }
    function isPalindrome4($x) {
        //全部翻转
        if($x<0){
            return false;
        }

        if($x<10){
            return true;
        } 

        $rev = '';
        $tmp = $x;
        while ($tmp>0) {
            # code...

            if($tmp<10){
                $rev .=$tmp;
                $tmp = 0;
            }else{
                $rev .= $tmp % 10;
                $tmp = (int) ($tmp/10);
            }

        }


        if($rev == $x){
            return true;
        }
        return false;

    }


    function isPalindrome3($x) {

        //对半翻转

        if($x<0){
            return false;
        }

        if($x<10){
            return true;
        } 
        //得到长度 
        $len =strlen((string)$x);

        if($len %2 !=0){
             //奇数情况
            $k = (int )($len/2);//左右各取的个数

            $left =   (int) ($x/pow(10,$k+1));
            $right = '';
            for ($i=0; $i < $k; $i++) { 
                # code...
                $right .= $x % 10;
                $x = (int) $x/10;
            }

            if($left == $right){
                return true;
            }
            return false;
            }else{
                //偶数情况
                $k = (int )($len/2);//左右各取的个数

                $left =   (int) ($x/pow(10,$k));
                $right = '';
                for ($i=0; $i < $k; $i++) { 
                    # code...
                    $right .= $x % 10;
                    $x = (int) $x/10;
                } 
                if($left == $right){
                    return true;
                }
                return false;
        }

    }
     //逐个字符比较

 function  isPalindrome4($x) {

     $x= (string)$x;

     $len = strlen($x);

     for($i=0;$i<$len;$i++){

     if($x[$i] !== $x[$len-1-$i]){  

     return  false;

            }

            }

     return  true;

    }
}

//TEST
$handle = new Solution();
$x = 1221; 

 $res = $handle->isPalindrome4($x) ;
 var_dump($res);

8. 字符串转换整数 (atoi)

/*
8. 字符串转换整数 (atoi)

请你来实现一个 myAtoi(string s) 函数,使其能将字符串转换成一个 32 位有符号整数(类似 C/C++ 中的 atoi 函数)。

函数 myAtoi(string s) 的算法如下:

读入字符串并丢弃无用的前导空格
检查下一个字符(假设还未到字符末尾)为正还是负号,读取该字符(如果有)。 确定最终结果是负数还是正数。 如果两者都不存在,则假定结果为正。
读入下一个字符,直到到达下一个非数字字符或到达输入的结尾。字符串的其余部分将被忽略。
将前面步骤读入的这些数字转换为整数(即,"123" -> 123, "0032" -> 32)。如果没有读入数字,则整数为 0 。必要时更改符号(从步骤 2 开始)。
如果整数数超过 32 位有符号整数范围 [−231,  231 − 1] ,需要截断这个整数,使其保持在这个范围内。具体来说,小于 −231 的整数应该被固定为 −231 ,大于 231 − 1 的整数应该被固定为 231 − 1 。
返回整数作为最终结果。
注意:

本题中的空白字符只包括空格字符 ' ' 。
除前导空格或数字后的其余字符串外,请勿忽略 任何其他字符。


示例 1:

输入:s = "42"
输出:42
解释:加粗的字符串为已经读入的字符,插入符号是当前读取的字符。
第 1 步:"42"(当前没有读入字符,因为没有前导空格)
         ^
第 2 步:"42"(当前没有读入字符,因为这里不存在 '-' 或者 '+')
         ^
第 3 步:"42"(读入 "42")
           ^
解析得到整数 42 。
由于 "42" 在范围 [-231, 231 - 1] 内,最终结果为 42 。
示例 2:

输入:s = "   -42"
输出:-42
解释:
第 1 步:"   -42"(读入前导空格,但忽视掉)
            ^
第 2 步:"   -42"(读入 '-' 字符,所以结果应该是负数)
             ^
第 3 步:"   -42"(读入 "42")
               ^
解析得到整数 -42 。
由于 "-42" 在范围 [-231, 231 - 1] 内,最终结果为 -42 。
示例 3:

输入:s = "4193 with words"
输出:4193
解释:
第 1 步:"4193 with words"(当前没有读入字符,因为没有前导空格)
         ^
第 2 步:"4193 with words"(当前没有读入字符,因为这里不存在 '-' 或者 '+')
         ^
第 3 步:"4193 with words"(读入 "4193";由于下一个字符不是一个数字,所以读入停止)
             ^
解析得到整数 4193 。
由于 "4193" 在范围 [-231, 231 - 1] 内,最终结果为 4193 。

*/


/*
本题主要是考察如何对循环的精准控制
如何控制循环的跳出  循环中的执行步骤的控制
*/

代码


class Solution {

    /**
     * @param String $s
     * @return Integer
     */
    function myAtoi($s) {

        $start  = 0; //刚开始
        $step1= ''; //符号位
        $step2= ''; //数字位

        $len = strlen($s);


        for ($i=0; $i < $len; $i++) { 

            $value = $s[$i];

            //1.读入字符串并丢弃无用的前导空格

            if($start == 0){
                if($value == ' '){
                    continue;
                }
                if($value == '+'|| $value == '-' ){
                    $start = 1;  // 符号位不再判断
                    $step1 = $value;
                    continue;
                }
                if(is_numeric($value)){
                    $start = 1;  //符号位不再判断
                    $step1 = '+';
                    $step2 .= $value;
                    continue;
                }

                //首位不是上述情况
                return  0;
            }

            //开始下一字符了
            if($start ==1){
                 //读入下一个字符,直到到达下一个非数字字符或到达输入的结尾。
                 if(!is_numeric($value)){
                    $numStr = (int) ($step1.$step2);

                    return $this->ret($numStr);
                 }else{
                    $step2 .= $value;
                 }
            }
        }
        //或到达输入的结尾。
        $numStr = (int) ($step1.$step2);

        return $this->ret($numStr);
    }

    public  function ret($numStr){



        $max = pow(2,31)-1;
        $min = pow(-2,31);
        if($numStr>$max){
            return $max;
        }

        if( $numStr<$min){
            return $min;
        }
        return $numStr;
    }
}


//TEST
$handle = new Solution();
$x =  "words and 987";  ' -423';// "+-12";//  '-5-';// '-12';//

echo  $res = $handle->myAtoi($x) ;

7. 整数反转

/*
给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。

如果反转后整数超过 32 位的有符号整数的范围 [−231,  231 − 1] ,就返回 0。

假设环境不允许存储 64 位整数(有符号或无符号)。


示例 1:

输入:x = 123
输出:321
示例 2:

输入:x = -123
输出:-321
示例 3:

输入:x = 120
输出:21
示例 4:

输入:x = 0
输出:0

*/

代码

class Solution {

    /**
     * @param Integer $x
     * @return Integer
     */

    function reverse2($x) {
        $flag = $x>=0 ? '' : '-';
        $x = $x>=0 ? $x : -$x;
        while($x){
            $str .= $x%10;
            $x =  (int) ($x/10);
        }
        $x = $flag.(int)$str;
        if($x> pow(2,31)-1 || $x < pow(-2,31)){
            return 0;
        }
        return  $x;
    }

    function reverse($x) {
        if($x>=0){
            $flag = '';
        }else{
            $flag = '-';
            $x = -$x;
        }

        $str = '';
        while($x){
            if($x<10){
                $str .= $x;
                $x = 0;
            } else{
                $str .= $x%10;
                $x =  $x/10;
                $x = (int) $x;
            }

        }
        $x = $flag.(int)$str;
        if($x> pow(2,31)-1 || $x < pow(-2,31)){
            return 0;
        }
        return  $x;
    }
}

//TEST
$handle = new Solution();
$x =    1234; 

echo  $res = $handle->reverse($x) ;

6. N 字形变换

/*
将一个给定字符串 s 根据给定的行数 numRows ,以从上往下、从左到右进行 Z 字形排列。

比如输入字符串为 "PAYPALISHIRING" 行数为 3 时,排列如下:

P   A   H   N

A P L S I I G

Y   I   R

之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:"PAHNAPLSIIGYIR"。

请你实现这个将字符串进行指定行数变换的函数:

string convert(string s, int numRows);

示例 1:

输入:s = "PAYPALISHIRING", numRows = 3

输出:"PAHNAPLSIIGYIR"

示例 2:

输入:s = "PAYPALISHIRING", numRows = 4

输出:"PINALSIGYAHRPI"

解释:

P     I    N

A   L S  I G

Y A   H R

P     I

示例 3:

输入:s = "A", numRows = 1

输出:"A"

*/
*/

想法

/* 
想法
将字符串按照N型排列存储在数组中,再依次横向读取得到结果
*/

代码

class Solution {

/**
 * @param String $s
 * @param Integer $numRows
 * @return String
 */
    function convert($s, $numRows) {
        $arrRes = [];  //存放结果

        $heng = 0;  //存放当前的横坐标
        $zong = 0;  //存放当前遍历的纵坐标

        $status = 0; //0 从上往下 1 从下往上 状态

        $strlen = strlen($s);
        for ($i=0; $i <$strlen ; ++$i) {
            $value =  $s[$i];

            if($status ==0){
                //从上往下时 
                if($zong< $numRows){
                    $arrRes[$zong][$heng] = $value;
                    $zong+=1;
                }else{
                    $status =1;
                    $zong-=1; //将超出的一次+1 回退回去
                }
            }

            if($status ==1){//var_dump($zong); exit;
                //从下往上时 ,一次只能放一个 ,除非zong-1 = 0

                $heng +=1;
                $zong -=1;

                $arrRes[$zong][$heng] = $value;

                if($zong == 0){
                   $status = 0;
                   $zong +=1; //将纵坐标的位置指向下一个 方便正向的插入
                }  
            }

        }
        return $arrRes;
    }
}

//TEST
$handle = new Solution();
$s =   "ABCD"; 

$res = $handle->convert($s,2) ;
 echo  bianli($res);



//二维数组的遍历

function bianli($arr)
{
    $str ='';
    foreach ($arr as $key => $value) {
        # code...
        foreach($value as $key2 => $value2){
            $str .= $value2;
        }
    }

    return $str;
}

5. 最长回文子串

/*
5. 最长回文子串
给你一个字符串 s,找到 s 中最长的回文子串。

如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。
示例 1:

输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。
示例 2:

输入:s = "cbbd"
输出:"bb" 
*/

/*
方式1: 

方式2:马拉车算法
即便我们使用了中央扩展法很易筛选出字符串中间的回文,但是其复杂度还是太高,达到 O(n^2)。
 当我们遇到字符串为“laaaaaaaaa”,之前的算法就会发生各个回文相互重叠的情况,
 会产生重复计算,然后就产生了一个问题,能否改进?
 答案是能,1975年,一个叫Manacher的人发明了Manacher Algorithm算法,俗称马拉车算法, 
 其时间复杂达到惊人的 O(n)。

方式3:中央扩展法
*/

代码

class  Solution {

 /**

* @param  String $s

* @return  String

     */

     //马拉车算法

     function  longestPalindrome($s)

    {

 $s_len = strlen($s);

 if ($s_len < 1) {

 return  '';

} elseif ($s_len <= 2) {

 return  $s[0] == $s[1] ? $s : $s[0];

        }  

 $symbol = '#';

 $s_with_symbol = "\$"  .  $symbol;

 for ($i = 0; $i < $s_len; $i ++) {

 $sub_s = $s[$i] .  $symbol;

 $s_with_symbol  .=  $sub_s;

        }

 $p = [];

 $mx = 0;

 $id = 0;

 $resLen = 0;

 $resCenter = 0;

 $s_with_symbol_len = strlen($s_with_symbol);

 for ($i = 1; $i < $s_with_symbol_len; $i ++) {

 $p[$i] = $mx > $i ? min($p[2 * $id - $i], $mx - $i) : 1;

 while ($s_with_symbol[$i + $p[$i]] == $s_with_symbol[$i - $p[$i]]) {

++ $p[$i];

 if ($mx < $p[$i] + $i) {

 $mx = $p[$i] + $i;

 $id = $i;

                }

 if ($resLen < $p[$i]) {

 $resLen = $p[$i];

 $resCenter = $i;

                }

            }

        }

 return  substr($s, ($resCenter - $resLen)/2, $resLen - 1);

    }

     //这个方式时间复杂度太高了 超时时间限制

     //两层for循环,遍历区间起始位置和终止位置,然后判断这个区间是不是回文。

     //时间复杂度:O(n^3)

     function  longestPalindrome2($s) {

 //暴力破解

 //逐个遍历,都找出正反

 $maxlen = 0;

 $maxString = '';

 $strlen = strlen($s);

 for ($i=0; $i <$strlen ; ++$i) {

 $str = '';

 for ($j=0; $j < $strlen; $j++) {

 # code...

 if($i+$j+1 >$strlen){

 break;

                }

 $str  .=  $s[$i+$j];

 //  $map[$str] = '';

 // echo "当前字符串{$str}".PHP_EOL;

 $fanzhuan = $this->fanzhuan($str);

 // echo "反转后为{$fanzhuan}".PHP_EOL;

 if($fanzhuan == $str && strlen($fanzhuan) > $maxlen){

 $maxString = $str;

 $maxlen = strlen($str);

                }

            }

        }

 return  $maxString;

     }
}     
function  fanzhuan($s)

     {

 $strlen = strlen($s);

 $str = '';

 for ($i=0; $i <$strlen ; ++$i) {

 $str  .=  $s[$strlen-$i-1];

        }

 return  $str;

     }

//TEST

$handle = new  Solution();

$s = "babad";

$res = $handle->longestPalindrome2($s) ;

var_dump($res);

4. 寻找两个正序数组的中位数

题目要求

/*
4. 寻找两个正序数组的中位数
给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。
算法的时间复杂度应该为 O(log (m+n)) 。
示例 1:

输入:nums1 = [1,3], nums2 = [2]
输出:2.00000
解释:合并数组 = [1,2,3] ,中位数 2
示例 2:

输入:nums1 = [1,2], nums2 = [3,4]
输出:2.50000
解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5
*/

想法

做这道题的时候思索过处理回文字符串在现实生活中具有什么意义?或者有哪些应用场景
不同于子串匹配,前缀匹配,回文匹配在工业界的确用得很少,几乎不会用到,因为确实没有可以对标的使用场景。有人说基因序列中自然的存在许多回文序列,所以权当练习题吧
/*
方式1:用php内置的 合并数组 排序数组
找到中位数并返回

方式二:本题考察的应该是数组的排序方法
可以依次比较注入一个新数组,因为其内部有序
*/

代码

class Solution {

function  findMedianSortedArrays2($nums1, $nums2) {

 $num1len = count($nums1);
 $nums2len =count($nums2);
 $letf = 0;
 $right = 0;
 $map = [];

 while($letf < $num1len || $right < $nums2len){
    if(isset($nums1[$letf]) && isset($nums2[$right])){
         if($nums1[$letf] < $nums2[$right]){
            echo  "左边小,录入左边".$nums1[$letf].PHP_EOL;
            $map[] = $nums1[$letf];
            $letf+=1;
          }else{
         echo  "右边小,录入右边".$nums2[$right].PHP_EOL;
        $map[] = $nums2[$right];
         $right+=1;
        }
     }elseif(isset($nums1[$letf]) ){
         echo  "只有左边,录入左边".$nums1[$letf].PHP_EOL;
         $map[] = $nums1[$letf]; $letf+=1;
     }elseif(isset($nums2[$right]) ){
         echo  "只有右边,录入右边".$nums1[$right].PHP_EOL;
         $map[] = $nums2[$right];$right+=1;
     }
    }

     $len = count($map);
     if($len %2 ==0){
     return ( $map[($len/2)-1] +  $map[($len/2)] ) /2;
     }else{  
     return $map[($len-1)/2];
     }
   }
  /**
   * @param Integer[] $nums1
   * @param Integer[] $nums2
   * @return Float
   */
  function findMedianSortedArrays($nums1, $nums2) {
    if(!$nums1 && !$nums2){
      return false;
    }

    $arr = array_merge($nums1, $nums2);

    $len = count($arr);
    if($len == 1){
      return $arr[0];
    }

    sort($arr);

    if($len %2 ==0){
       return ( $arr[($len/2)-1] +  $arr[($len/2)] ) /2;
    }else{  
      return  $arr[($len-1)/2];
    }

  }
}

//TEST
$handle = new Solution();
$nums1 = [1,2];
$nums2 = [3,4];
$res = $handle->findMedianSortedArrays($nums1, $nums2) ;
var_dump($res);

3. 无重复字符的最长子串

题目要求

/*
给定一个字符串 `s` ,请你找出其中不含有重复字符的 **最长子串 **的长度。
示例 1:

输入: s = "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:

输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:

输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
     请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
*/

想法:

方式1:
创建一个哈希表
放置每次未重复前的 值 
遇到重复的 ,保存当前长度 ,删除数组中重复的以及之前的值
再次往后遍历录入
最后对比长度  (或是直接每次对比长度)

方式2-   利用滑动窗口的思想,动态维护窗口左右边界的准确性即可。
//方式2
/*
//双指针法 动态维护窗口左右边界的准确性
//左右指针都指向第一个 初始化
//右指针一直往前指
//如果遇到重复项
//比较窗口值的大小
//左指针指向重复项+1的位置即可
//注意 要防止左指针回退
*/
function  lengthOfLongestSubstring40($s) {
 $left = 0;
 $right = 0;
 $maxLen = 0;
 $map = [];
 $strlen = strlen($s);

 for ($i=0; $i <$strlen ; ++$i) {
         $value =$s[$i];
        if(isset($map[$value]) && $map[$value]>=$left){ //防止左指针回退 
        $map[$value]>=$left
        //计算此时窗口大小
        $len = $right - $left;
        //移动左指针之前,比较最大窗户
        $maxLen = $maxLen > $len ? $maxLen :$len;
        //遇到重复了 ,左指针移动到重复项之前的值里的下一位
        $left = $map[$value]  +1;
        }

        $right +=1;//右指针往前指  
        $len = $right - $left;
        //修正map 里重复值的位置下标
        $map[$value] =  $i;
    }
    $currentLen = $right - $left;
    return  $maxLen = $maxLen > $currentLen ? $maxLen : $currentLen;
}

//方式1
function lengthOfLongestSubstring($s) {
        $maxLen = 0;
        $map = [];  
        $strlen = strlen($s);
        for ($i=0; $i <$strlen ; ++$i) {
            $value =  $s[$i]; 
            if(!isset($map[$value])){
                $map[$value] = '' ;
            }else{
                $currentLen = count($map);
                $maxLen = $maxLen > $currentLen ? $maxLen : $currentLen;

                foreach ($map as $key =>$tmp) {
                        if( $key == $value){
                            unset($map[$key]);
                            break;
                        }else{
                            unset($map[$key]);
                        }
                }
                $map[$value] = '';  
            }
        }
        $currentLen = count($map);
        return $maxLen = $maxLen > $currentLen ? $maxLen : $currentLen;
     }

//TEST
$handle = new  Solution();
$s = "iqbtbscgdztpgfp";//"bbbbb";//"bpfbhmipx";//"tmmzuxt";//"asjrgapa";
$res = $handle->lengthOfLongestSubstring($s) ;
var_dump($res);

2.两数相加

题目要求

/*
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。

请你将两个数相加,并以相同形式返回一个表示和的链表。

你可以假设除了数字 0 之外,这两个数都不会以 0 开头。

示例1:
**输入:**
l1 = [2,4,3], 
l2 = [5,6,4]
**输出:**[7,0,8]
**解释:**342 + 465 = 807.

示例 2:

输入:l1 = [0], l2 = [0]
输出:[0]
示例 3:

输入:l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]
输出:[8,9,9,9,0,0,0,1]

*/
<?php

/**
 * Definition for a singly-linked list.
 * class ListNode {
 *     public $val = 0;
 *     public $next = null;
 *     function __construct($val = 0, $next = null) {
 *         $this->val = $val;
 *         $this->next = $next;
 *     }
 * }
 * 
 * 大数相加的实现  
 */

 class ListNode {
      public $val = 0;
      public $next = null;
      function __construct($val = 0, $next = null) {
          $this->val = $val;
          $this->next = $next;
     }
}

class Solution {

    /**
     * @param ListNode $l1
     * @param ListNode $l2
     * @return ListNode
     */
    //数组实现
    ////数组遍历相加,把数组的值全部存在一个数组里
    //先找出较长的数组
    function addTwoNumbers($l1, $l2) {

        $len1 = count($l1);
        $len2 = count($l2);
        $l3 = $len1 > $len2 ? $l1 :$l2; 
        $l4 = $len1 > $len2 ? $l2 :$l1;
        $a = 0;
        $map = [];
        foreach ($l3 as $key => $value) {

            if(isset($l4[$key])){
                // var_dump($value,$l4[$key],$a);
                  $res =  $value + $l4[$key] + $a;
                if($res > 9){
                    $map[] = $res-10;
                    $a = 1;
                }else{
                    $map[] = $res;
                    $a = 0;
                }
            }else{
                if($a == 1){
                    $map[] = 1;
                    $a = 0;
                }else{
                    $map[] = 0;
                }
            }
        }
        if($a = 1){
            $map[] = 1;
        }

        return $map;
    }

    //本题考察的是对于链表这种数据结构的应用
    //链表实现
    //这里面应该还涉及到一个浅拷贝 深拷贝的知识点  这里 $cur = $dummyHead; 应该是浅拷贝 ,没有开辟新的堆栈

    function addTwoNumbers2($l1, $l2) {
        $carry = 0; // 进位
        $dummyHead = new ListNode(0); // 添加虚拟头节点, 方便返回
        $cur = $dummyHead;

        while($l1!== null || $l2!=null || $carry){
            $sum = $carry;
            if($l1!=null){
                $sum += $l1->val;
                // echo $sum;
                $l1 = $l1->next;
            }
            if($l2!=null){
                $sum += $l2->val;
                $l2 = $l2->next;
            }
            if($sum > 9){
                $sum -=10;
                $carry = 1; 
            }else{
                $carry = 0;//复位
            }
            // echo $sum.'<br>';
            $cur->next = new ListNode($sum);  //这里返回的是一个新节点
            $cur  = $cur->next; //这里进行了节点的挂载
            // var_dump($dummyHead);
        }
        return $dummyHead->next;
    }
}

//TEST
// $handle = new Solution();
// // $l1 = [2,4,3];
// // $l2 = [5,6,4];
// // $l1 = [0];
// // $l2 = [0];
// $l1 =  [9,9,9,9,9,9,9];
// $l2 = [9,9,9,9];
// $res = $handle->addTwoNumbers($l1, $l2) ;
// var_dump($res);


//TEST List
$handle = new Solution();
$l1 = getList([9,9,9,9,9,9,9]) ;
$l2 = getList([9,9,9,9]) ;
$res = $handle->addTwoNumbers2($l1, $l2) ;
 var_dump(getArray($res));
 var_dump(getString($res));

//把数组形式录入成链表
function getList($arr){
    $list = new ListNode(0);
    $cur = $list;
    foreach ($arr as $key => $value) {
        # code...
        $cur->next = new ListNode($value);
        $cur = $cur->next;
    }
    return $list->next;
}

//把链表返回成数组
function getArray($list){
    $arr = [];
    while($list !=null) {
        $arr[] = $list->val;
        $list = $list->next;
    }
    return $arr;
}

function getString($list){
    $a = '';
    while($list !=null) {
        $a .= $list->val;
        $list = $list->next;
    }
    return $a;
}

1.两数之和

题目要求

/*
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target  的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。



示例 1:

输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
示例 2:

输入:nums = [3,2,4], target = 6
输出:[1,2]
示例 3:

输入:nums = [3,3], target = 6
输出:[0,1]

2 <= nums.length <= 104
-109 <= nums[i] <= 109
-109 <= target <= 109
只会存在一个有效答案


进阶:你可以想出一个时间复杂度小于 O(n2) 的算法吗?
*/

想法

1.遍历 复杂度 O(n2)

2.设计一个辅助数组,用辅助数组的键来保存原数组的值,用辅助数组的值来保存原数组的键
在依次遍历的时候,只需要查询 目标值减去当前遍历到的值  所对应的辅助数组的键存不存在即可
不存在则录入辅助数组,存在则返回辅助数组对应的值(原数组中的数值位置)和当前遍历到的位置

代码

class Solution {

    /**
     * @param Integer[] $nums
     * @param Integer $target
     * @return Integer[]
     */
    //遍历
    function twoSum($nums, $target) {
        $len = count($nums) ;
        for($i=0;$i<$len-1;$i++){
            for ($j=$i+1; $j <$len ; $j++) { 
                if($nums[$i]+$nums[$j] == $target){
                    return [$i,$j] ;
                } 
            }
        }
        return false;
    }

    //辅助数组
    function twoSum2($nums, $target) {
        $tmp = [];
        foreach($nums as $key => $value){
            if(isset($tmp[$target-$value])){
                return [$tmp[$target-$value],$key];
            }
            $tmp[$value] = $key;
        }
        return false;
    }
}

//TEST
$handle = new Solution();
$nums = [0,4,3,0];
$target = 0;
$res = $handle->twoSum($nums, $target) ;
var_dump($res);

总结:

  • 方法一:暴力枚举
    • 时间复杂度:O(N2)
    • 空间复杂度:O(1)
  • 方法二:哈希表
    • 散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。
    • 时间复杂度:O(N)
    • 空间复杂度:O(N)

本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 1
  • 哈希表
class Solution {

    function twoSum($nums, $target) {
        $size = count($nums);
        $map = [];
        for ($i = 0; $i < $size; $i++) {
            if (isset($map[$target - $nums[$i]])) {
                return [$i, $map[$target - $nums[$i]]];
            }
            $map[$nums[$i]] = $i;
        }
        return false;
    }
}
1年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!