LeetCode刷题笔记(7)

LeetCode刷题笔记(7)

背景

今天是刷LeetCode的第七天,嗯,没有那么难受以及无法接受了,感觉还可以。今天结束了贪心算法的最后三道题目,明天就是二分法了。

763、划分字母区间

  • 输入:S = “ababcbacadefegdehijhklij”
  • 输出:[9,7,8]
  • 解释:
  • 划分结果为 “ababcbaca”, “defegde”, “hijhklij”。
  • 每个字母最多出现在一个片段中。
  • 像 “ababcbacadefegde”, “hijhklij” 的划分是错误的,因为划分的片段数较少。
    解题思路:
    策略就是不断地选择从最左边起最小的区间。可以从第一个字母开始分析,
    假设第一个字母是 ‘a’,那么第一个区间一定包含最后一次出现的 ‘a’。
    但第一个出现的 ‘a’ 和最后一个出现的 ‘a’ 之间可能还有其他字母,
    这些字母会让区间变大。举个例子,在 “abccaddbeffe” 字符串中,
    第一个最小的区间是 “abccaddb”。
    通过以上的分析,我们可以得出一个算法:对于遇到的每一个字母,
    去找这个字母最后一次出现的位置,用来更新当前的最小区间。
    算法:
    定义数组 last[char] 来表示字符 char 最后一次出现的下标。
    定义 anchor 和 j 来表示当前区间的首尾。
    如果遇到的字符最后一次出现的位置下标大于 j,
    就让 j=last[c] 来拓展当前的区间。
    当遍历到了当前区间的末尾时(即 i==j ),
    把当前区间加入答案,同时将 start 设为 i+1 去找下一个区间。
public class partitionLabels763 {
    public List<Integer> partitionLabels(String S) {
        int[] last = new int[26];
        for(int i = 0; i <S.length(); ++i){
            last[S.charAt(i)-'a']=i;
        }
        //for循环通过相同的字符作为下标来覆盖,
        // 从而得到最后一个字符的位置,好奇妙啊
        int j = 0,anchor = 0;
        List<Integer> ans = new ArrayList<>();
        for(int i = 0; i <S.length();++i){
            j = Math.max(j,last[S.charAt(i)-'a']);
            if(i == j){
                ans.add(i-anchor+1);
                anchor = i +1;
            }
        }
        return ans;

    }
}

总结:这道题目是中等难度的,官方给的答案非常巧妙。比如找到数组中某字母最后以此出现的位置,第一个for循环就利用覆盖来实现这种思想,我觉得非常好。稍微还是比较难想到的,利用j与last出现的下标进行比较。难就难在如何转化题目的含义。

665、判断非递减序列

  • 给你一个长度为 n 的整数数组,
  • 请你判断在 最多 改变 1 个元素的情况下,
  • 该数组能否变成一个非递减数列。
  • 我们是这样定义一个非递减数列的:
  • 对于数组中所有的 i (0 <= i <= n-2),
  • 总满足 nums[i] <= nums[i + 1]。
    解题思路:
    在出现 nums[i] < nums[i - 1] 时,
    需要考虑的是应该修改数组的哪个数,
    使得本次修改能使 i 之前的数组成为非递减数组,
    并且 不影响后续的操作 。优先考虑令 nums[i - 1] = nums[i],
    因为如果修改 nums[i] = nums[i - 1] 的话,
    那么 nums[i] 这个数会变大,就有可能比 nums[i + 1] 大,
    从而影响了后续操作。
    还有一个比较特别的情况就是 nums[i] < nums[i - 2],
    修改 nums[i - 1] = nums[i] 不能使数组成为非递减数组,
    只能修改 nums[i] = nums[i - 1]。
public class checkPossibility665 {
    public boolean checkPossibility(int[] nums){
        int cnt = 0;
        for(int i = 1; i <nums.length &&cnt<2;i++){
            if(nums[i]>nums[i-1]){
                continue;
            }
            cnt++;
            if(i-2>=0 && nums[i-2]>nums[i]){
                nums[i]=nums[i-1];
            }else{
                nums[i-1]=nums[i];
            }
        }
        return cnt <=1;
    }
}

总结:这道题目最难的地方在于想到i-2与i之间的大小关系,与我最初的想法不同,我本来的想法是计算出导致它不是递减的个数必须要小于nums.length-2

53、子数组最大的和

  • 输入: [-2,1,-3,4,-1,2,1,-5,4],
  • 输出: 6
  • 解释: 连续子数组 [4,-1,2,1] 的和最大,为 6
public class maxSubArray53 {
    public int maxSubArray(int[] nums){
        if(nums==null||nums.length==0) {
            return 0;
        }
        int preSum = nums[0];
        int maxSum = preSum;
        for(int i = 1; i < nums.length; i++){
            preSum = preSum>0 ? preSum+nums[i]:nums[i];
            maxSum = Math.max(maxSum,preSum);
        }
     return maxSum;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值