代码随想录算法训练营第二十五天 | leetcode:分发饼干 ,摆动序列,最大子数组和

455. 分发饼干

注意的地方

  1. 每个孩子最多只能给一块饼干。
  2. 目标是尽可能满足越多数量的孩子。

解题方法

先将数组从小到大排序,同时遍历孩子数组与饼干数组。以饼干数值最大值开始匹配符合条件的孩子,如果找到了那么同时跳过该饼干和孩子元素,进行新一轮的匹配,直到遍历完成。
代码随想录算法训练营第二十四天 | leetcode:递增子序列 ,全排列,全排列II

复杂度

时间复杂度

O(nlogn)

空间复杂度

O(1)

code

class Solution {

    /**
     * @param Integer[] $g
     * @param Integer[] $s
     * @return Integer
     */
    function findContentChildren($g, $s) {
        $i = count($g) - 1;
        $j = count($s) - 1;
        $count = 0;
        //排序方便从大到小遍历
        sort($g);
        sort($s);
        while($i >= 0 && $j >= 0){
            //print_r([$i,$j]);
            //如果最大饼干分发出去则,孩子胃口数组与饼干尺寸数组下标都向左移动
            if($s[$j] >= $g[$i]){
                $i--;
                $j--;
                $count++;
            }else{
                //如果饼干没分发出去,则孩子往左移,匹配胃口更小的孩子
                $i--;
            }
        }
        return $count;
    }
}

376. 摆动序列

注意的地方

仅有一个元素或者含两个不等元素的序列也视作摆动序列。 也就是说一个元素最长子序列的长度为1,两个不等元素的序列的最长子序列的长度为2,重复元素视为一个长度。
所以题目中需要特别注意数组中含有重复元素的情况。

解题方法

  1. 将题目中的摆动抽象成上升沿与下降沿,会方便理解。
  2. 此题要考虑的情况非常多,一次性考虑清楚真的非常难。debug了一个多小时才把所有情况补上:tired_face: :tired_face::tired_face:
  • 只有一个元素
  • 只有两个元素,且元素不相同
  • 只有两个元素,且元素相同
  • 大于两个元素,且元素都相同
    代码随想录算法训练营第二十四天 | leetcode:递增子序列 ,全排列,全排列II
  • 大于两个元素,元素相邻之间互不相同
    代码随想录算法训练营第二十四天 | leetcode:递增子序列 ,全排列,全排列II
  • 大于两个元素,元素相邻之间有部分相同
    代码随想录算法训练营第二十四天 | leetcode:递增子序列 ,全排列,全排列II
    代码随想录算法训练营第二十四天 | leetcode:递增子序列 ,全排列,全排列II
  • 大于两个元素,单调递增/递减,元素相邻互不相同
    代码随想录算法训练营第二十四天 | leetcode:递增子序列 ,全排列,全排列II
  • 大于两个元素,单调递增/递减,元素相邻有部分相同
    代码随想录算法训练营第二十四天 | leetcode:递增子序列 ,全排列,全排列II
  1. 默认两边是存在两个子序列长度的,所以子序列长度count从2开始递增,循环遍历从1开始,一直到count(nums)-2,遇到一个顶峰(上顶峰或者下顶峰)count++即可。需要特殊处理,中间有相同元素的情况,因为即使有相同元素梯形也只算一个序列长度,所以使用while跳过相同元素后,判断趋势是否相反,相反count++,同时更新循环索引i,避免重复循环即可。

复杂度

时间复杂度

O(n)

空间复杂度

O(1)

code

class Solution {

    /**
     * @param Integer[] $nums
     * @return Integer
     */
    function wiggleMaxLength($nums) {
        if(count($nums) == 1) return 1;
        if(count($nums) == 2){
            //两个元素互不相同的情况
            if($nums[0] != $nums[1]){
                return 2;
            }else{
                return 1;
            }
        }
        //nums元素都相同的情况
        $check = array_unique($nums);
        if(count($check) == 1) return 1;
        $i = 1;//默认第一位是一个子序列长度,所以从1开始
        $count = 2;//默认首尾等于两个子序列长度,所以count从2开始
        //默认末尾为一个子序列长度,所以只遍历到count($nums) - 1停止即可,否则会溢出
        while($i < count($nums) - 1){
            //左右相邻不相等的情况 且当前为上顶峰的情况
            if($nums[$i] - $nums[$i-1] > 0 && $nums[$i + 1] - $nums[$i] < 0){
                $count++;
            }
            //左右相邻不相等的情况 且当前为下顶峰的情况
            if($nums[$i] - $nums[$i-1] < 0 && $nums[$i + 1] - $nums[$i] > 0){
                $count++;
            }
            //下一个是相同元素 且当前为下降沿的情况
            if($nums[$i] - $nums[$i-1] < 0 && $nums[$i + 1] == $nums[$i]){
                $j = $i + 2;
                //获取下一个不同的值
                while($j < count($nums) - 1 && $nums[$i] == $nums[$j]){
                    $j++;
                }
                //判断与当前趋势不同则++,并且更新i
                if($nums[$j] > $nums[$i]){
                    $count++;
                    $i = $j - 1;//因为下面有i++所以需要-1,否则就跳过$nums[$j] 元素了;
                }
            }
            //下一个是相同元素 且当前为上升沿的情况
            if($nums[$i] - $nums[$i-1] > 0 && $nums[$i + 1] == $nums[$i]){
                $k = $i + 2;
                //获取下一个不同的值
                while($k < count($nums) - 1 && $nums[$i] == $nums[$k]){
                    $k++;
                }
                //判断与当前趋势不同则++,并且更新i
                if($nums[$k] < $nums[$i]){
                    $count++;
                    $i = $k - 1;//因为下面有i++所以需要-1,否则就跳过$nums[$j] 元素了;
                }
            }
            $i++;
        }

        return $count;
    }
}

53. 最大子数组和

注意的地方

  1. 子数组是数组中的一个连续部分。
  2. 子数组最少包含一个元素。

解题方法

  1. 如果 -2 1 在一起,计算起点的时候,一定是从 1 开始计算,因为负数只会拉低总和,这就是贪心贪的地方!
  2. 局部最优:当前“连续和”为负数的时候立刻放弃,从下一个元素重新计算“连续和”,因为负数加上下一个元素 “连续和”只会越来越小。
  3. 全局最优:选取最大“连续和”、局部最优的情况下,并记录最大的“连续和”,可以推出全局最优。
  4. 从代码角度上来讲:遍历 nums,从头开始用 count 累积,如果 count 一旦加上 nums[i]变为负数,那么就应该从 nums[i+1]开始从 0 累积 count 了,因为已经变为负数的 count,只会拖累总和。

复杂度

时间复杂度

O(n)

空间复杂度

O(1)

code

class Solution {

    /**
     * @param Integer[] $nums
     * @return Integer
     */
    function maxSubArray($nums) {
        $max = PHP_INT_MIN;
        $count = 0;
        for($i = 0; $i < count($nums); $i++){
            $count += $nums[$i];
            //更新最大值
            $max = max($max, $count);
            //当前连续和小于0,则丢弃,从下一个元素开始累加。因为负数加上任何数都会比原来小。
            if($count < 0) $count = 0;
        }
        return $max;
    }
}
本作品采用《CC 协议》,转载必须注明作者和本文链接
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

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