【每日三题】长度最小的子数组

124 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第17天,点击查看活动详情 >>

每日三刷,剑指千题

计划简介:

  • 每日三题,以中等题为主,简单题为辅进行搭配。保证质量题1道,数量题3道。
  • 每日早通勤在LeetCode手机端选题,思考思路,没答案的直接看题解。
  • 每日中午进行编码,时间控制在一小时之内。
  • 下班前半小时进行整理总结,并发布到掘金每日更文活动。

说明:

  • 基于以前的刷题基础,本次计划以中等题为主,大部分中等题都可以拆分为多个简单题,所以数量保证3,质量保证一道中等题即可。
  • 刷题顺序按照先刷链表、二叉树、栈、堆、队列等基本数据结构,再刷递归、二分法、排序、双指针等基础算法,最后是动态规划、贪心、回溯、搜索等复杂算法。
  • 刷题过程中整理相似题型,刷题模板。
  • 目前进度 139/1000

[167]两数之和 II - 输入有序数组

给你一个下标从 1 开始的整数数组 numbers ,该数组已按 非递减顺序排列 ,请你从数组中找出满足相加之和等于目标数 target 的两个数。如果设这两个数分别是 numbers[index1]numbers[index2] ,则 1 <= index1 < index2 <= numbers.length

以长度为 2 的整数数组 [index1, index2] 的形式返回这两个整数的下标 index1index2

你可以假设每个输入 只对应唯一的答案 ,而且你 不可以 重复使用相同的元素。

你所设计的解决方案必须只使用常量级的额外空间。

示例 1:

输入:numbers = [2,7,11,15], target = 9
输出:[1,2]
解释:2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。返回 [1, 2] 。

解析

Code

class Solution {
        public int[] twoSum(int[] numbers, int target) {
            int[] ans = new int[2];
            // 如何更快的寻找第二个数
            for (int i = 0; i < numbers.length; i++) {
                int first = numbers[i];
                int left = i + 1;     // 左端点
                int right = numbers.length - 1; // 右
                while (left <= right) {
                    int mid = (right - left) / 2 + left;
                    if (numbers[mid] + first == target) {
                        ans[0] = i + 1;
                        ans[1] = mid + 1;
                        return ans;
                    } else if (numbers[mid] + first > target) {
                        // 修改端点
                        right = mid - 1;
                    } else {
                        left = mid + 1;
                    }
                }
            }
            return ans;
        }
    }

[209]长度最小的子数组

给定一个含有 n 个正整数的数组和一个正整数 target

找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度 如果不存在符合条件的子数组,返回 0

示例 1:

输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。

解析

>= target 坑死

Code

class Solution {
        public int minSubArrayLen(int target, int[] nums) {
            // 练习 前缀和 + 二分 (双指针也可)
            int ans = Integer.MAX_VALUE;
            if (nums.length == 0) return 0;
            // 构建 前缀和 单调递增
            int[] sum = new int[nums.length + 1];
            for (int i = 1; i < sum.length; i++) {
                sum[i] = nums[i - 1] + sum[i - 1];
            }
​
            for (int i = 0; i < sum.length; i++) {
                int s = sum[i];
                // 在前缀和数组 二分查找
                int left = 0, right = i;
                while (left < right) {
                    int mid = (left + right + 1) / 2;
                    if (sum[mid] <= s - target) {
                        left = mid;
                    } else {
                        right = mid - 1;
                    }
                }
                if (sum[right] <= s - target) {
                    ans = Math.min(ans, i - right);
                }
            }
            return ans == Integer.MAX_VALUE ? 0 : ans;
        }
    }

[704]二分查找

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1

示例 1:

输入: nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为 4

解析

二分模板,记住int mid = (left+right+1)/2;

Code

class Solution {
    public int search(int[] nums, int target) {
        int left = 0,right = nums.length -1;
        while (left<=right){
            int mid = (left+right+1)/2;
            if (nums[mid] == target){
                return mid;
            }else if (nums[mid] < target){
                left = mid + 1;
            }else {
                right = mid -1;
            }
        }
        return -1;
    }
}

\