算法训练day25 | php | 455.分发饼干 , 376. 摆动序列 , 53. 最大子序和

一、力扣题455. 分发饼干

假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。

对每个孩子 i,都有一个胃口值 g[i],这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j,都有一个尺寸 s[j] 。如果 s[j] >= g[i],我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。

示例 1:

输入: g = [1,2,3], s = [1,1]
输出: 1
解释: 
你有三个孩子和两块小饼干,3个孩子的胃口值分别是:1,2,3。
虽然你有两块小饼干,由于他们的尺寸都是1,你只能让胃口值是1的孩子满足。
所以你应该输出1。

示例 2:

输入: g = [1,2], s = [1,2,3]
输出: 2
解释: 
你有两个孩子和三块小饼干,2个孩子的胃口值分别是1,2。
你拥有的饼干数量和尺寸都足以让所有孩子满足。
所以你应该输出2.

提示:

  • 1 <= g.length <= 3 * 104
  • 0 <= s.length <= 3 * 104
  • 1 <= g[i], s[j] <= 231 - 1

        有两种方法,先把两个数组按升序排列,可以把两个数组头部对齐,也可以把两个数组尾部对齐来遍历。

        1、头部对齐:先把小饼干分给小胃口的孩子。从前往后遍历,当当前饼干小于对应的胃口时,不能遍历下一个胃口,因为之后的胃口会更大,更无法满足,所以就要拿下一个更大的饼干来满足当前胃口,所以饼干是移动的,胃口是固定的,所以在for循环中,应该是拿饼干的数组来循环。

        

function findContentChildren($g, $s) {
        sort($g);
        sort($s);
        $j = 0;
        $num = 0;
        for($i = 0; $i < count($s); $i++) {
            if($j < count($g) && $s[$i] >= $g[$j]) {
                $j++;
                $num++;
            }
        }
        return $num;
    }

        2、尾部对齐:先把大饼干分给大胃口的孩子。即从后往前遍历,当当前饼干小于对应的胃口值时,就往前遍历找更小的胃口,所以胃口是移动的,饼干是固定的。

function findContentChildren($g, $s) {
        sort($g);
        sort($s);
        $j = count($s) - 1;
        $num = 0;
        for($i = count($g) - 1; $i >= 0; $i--) {
            if($j >= 0 && $g[$i] <= $s[$j]) {
                $num++;
                $j--;
            }
        }
        return $num;
    }

二、力扣题376. 摆动序列

如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为 摆动序列 。第一个差(如果存在的话)可能是正数或负数。仅有一个元素或者含两个不等元素的序列也视作摆动序列。

  • 例如, [1, 7, 4, 9, 2, 5] 是一个 摆动序列 ,因为差值 (6, -3, 5, -7, 3) 是正负交替出现的。

  • 相反,[1, 4, 7, 2, 5] 和 [1, 7, 4, 5, 5] 不是摆动序列,第一个序列是因为它的前两个差值都是正数,第二个序列是因为它的最后一个差值为零。

子序列 可以通过从原始序列中删除一些(也可以不删除)元素来获得,剩下的元素保持其原始顺序。

给你一个整数数组 nums ,返回 nums 中作为 摆动序列 的 最长子序列的长度 。

示例 1:

输入:nums = [1,7,4,9,2,5]
输出:6
解释:整个序列均为摆动序列,各元素之间的差值为 (6, -3, 5, -7, 3) 。

示例 2:

输入:nums = [1,17,5,10,13,15,10,5,16,8]
输出:7
解释:这个序列包含几个长度为 7 摆动序列。
其中一个是 [1, 17, 10, 13, 10, 16, 8] ,各元素之间的差值为 (16, -7, 3, -3, 6, -8) 。

示例 3:

输入:nums = [1,2,3,4,5,6,7,8,9]
输出:2

提示:

  • 1 <= nums.length <= 1000
  • 0 <= nums[i] <= 1000

         本题的思路是把单调坡度上的节点舍弃 ,只考虑峰值与谷底的值,如图所示:只选中被红圈圈住的内容。设 pre 为 nums[ i ] - nums[ i - 1], cur 为 nums[ i + 1] - nums[ i ]。则判断锋值或谷值的条件为: pre > 0 && cur < 0  或  pre < 0 && cur > 0。

        但需要考虑特殊情况:

        一、锋头或谷底是平坡 :

                如图所示,显然在平坡上只能选择一个值作为锋值,这里默认选择最右边的值作为锋值,这时判断条件就添加了内容,变成了判断峰值和谷值为: pre >= 0 && cur < 0  或  pre <= 0 && cur > 0。

        

        二、首尾两端的特殊情况:

        首尾两端一个缺少 pre, 一个缺少 cur,不能通过上面的判断条件,所以得特殊对待。有两种情况,1、是首尾两端不在平坡上,这样的两端天然就是峰值或者谷值。2、是首尾两端在平坡上,因为我们是取平坡上最右边的节点,所以首端会被舍弃,而尾端作为最右边的值肯定会被保留。

        所以得出结论,尾端肯定会被保留,而首端需要判断 cur 是否为 0。这时可以假设首端的 pre 为 0,这样当首端的 pre = 0 && cur = 0时会被舍弃,当 pre = 0 && cur != 0 时会被保留。这样的判断条件符合以上的判断条件。

        所以一开始 result 就会 + 1,加的这个 1 是尾端的节点。

        三、单调坡上有平坡:

         按照上面的判断条件,图中圈中的 3 也会被保留,但实际上是不应该被保留的。所以需要改变的是 pre 的值的设置,上面的 pre 是指当前元素与上一个元素的对比,但如果上一个元素与当前元素相等,就会造成以上这种错误。

        所以 pre 不应该是当前元素与上一个元素的对比,而是当前元素与在该元素之前最近的不相等元素的对比。换句话说就是 pre 在当前元素符合判断条件之后,才会将 pre 设为当前元素的 cur,否则就不更新。

        例如上图,在遇到第一个 3 时,因为这个 3 不符合判断条件,所以 pre 不更新,此时的 pre 还是  > 0 的状态,然后遇到第二个 3 ,发现 pre > 0 且 cur > 0,不符合条件,跳过,pre继续不变,这样就不会出现错误了。

function wiggleMaxLength($nums) {
        $pre = 0;
        $cur = 0;
        $num = 1;
        for($i = 0; $i < count($nums) - 1; $i++) {
            $cur = $nums[$i + 1] - $nums[$i];
            if(($pre <= 0 && $cur > 0) || ($pre >= 0 && $cur < 0)) {
                $num++;
                $pre = $cur;
            }
        }
        return $num;
    }

三、力扣题53. 最大子数组和

给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

子数组 是数组中的一个连续部分。

示例 1:

输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。

示例 2:

输入:nums = [1]
输出:1

示例 3:

输入:nums = [5,4,-1,7,8]
输出:23

提示:

  • 1 <= nums.length <= 105
  • -104 <= nums[i] <= 104

        这个题目的难点在于,在加总和时,什么时候应该舍弃当前的数组,从新的位置开始加总和。

        1、当总和加一个元素后反而比之前小。这种情况可以舍弃吗?实际上是不可以的。就像题目的例3的数组:[5, 4, -1, 7, 8],虽然加上 - 1后总和暂时小了,但加上之后的值就是最大的。

        2、当总和小于0时,这时候就可以舍弃当前数组了。这说明当前数组的和已经是拖累了,加上任何数都只会更小。

        另外还需要有一个值 max,用于记录添加元素过程中总和的最大值,毕竟是把数组从头添加到尾,最大值很可能是出现在中间的添加过程中。

function maxSubArray($nums) {
        $sum = 0;
        $res = PHP_INT_MIN;
        for($i = 0; $i < count($nums); $i++) {
            $sum += $nums[$i];
            if($sum > $res) $res = $sum;
            if($sum < 0) $sum = 0;
        }
        return $res;
    }

        

        

        

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值