1、数组

代码随想录
LeetCode 题解
数组问题最常见
滑动窗口:窗口大小固定还是不固定,什么时候应该扩展窗口

1、二分查找

704 - 二分查找
更多二分查找

public int search(int[] nums, int target) {
    int l = 0;
    int r = nums.length - 1;
    int mid;

    while (l <= r) {
        mid = l + (r - l) / 2;
        if (nums[mid] == target) return mid;
        if (nums[mid] > target) r = mid - 1;
        else l = mid + 1;
    }

    return -1;
}

2、移除元素

27 - 移除元素

public int removeElement(int[] nums, int val) {
    // [end ... nums.length - 1] = val
    int end = nums.length;
    int i = 0;
    while (i < end) {
        if (nums[i] == val) swap(nums, i, --end);
        else i++;
    }
    return end;
}

private void swap(int[] nums, int a, int b) {
    int k = nums[a];
    nums[a] = nums[b];
    nums[b] = k;
}

3、有序数组的平方

977 - 有序数组的平方

public int[] sortedSquares(int[] nums) {
    int[] arr = new int[nums.length];
    int i = arr.length - 1;

    // 合并两个降序数组, 得到一个升序数组
    int p1 = 0;
    int p2 = nums.length - 1;
    while (p1 <= p2) {
        if (Math.abs(nums[p1]) > Math.abs(nums[p2])) {
            arr[i--] = nums[p1] * nums[p1];
            p1++;
        } else {
            arr[i--] = nums[p2] * nums[p2];
            p2--;
        }
    }

    return arr;
}

4、长度最小的子数组

209 - 长度最小的子数组
滑动窗口

窗口大小不固定,和小于目标的时候应该扩展窗口

public int minSubArrayLen(int target, int[] nums) {
    int l = 0, r = -1; // [l ... r] 是滑动窗口
    int sum = 0;       // sum = 滑动窗口的和
    int res = nums.length + 1;

    // 窗口的左边界在数组范围内, 则循环继续
    while (l < nums.length) {
        if (r + 1 < nums.length && sum < target) sum += nums[++r];
        else sum -= nums[l++];

        if (sum >= target) res = Math.min(res, r - l + 1);
    }

    return res != nums.length + 1 ? res : 0;
}

5、螺旋矩阵 II

59 - 螺旋矩阵 II

// l   r
// 1 2 3 t
// 8 9 4
// 7 6 5 b
public int[][] generateMatrix(int n) {
    int[][] arr = new int[n][n];
    int num = 1;
    int left = 0, right = n - 1;
    int top = 0, bottom = n - 1;

    while (num <= n * n) {
        for (int i = left; i <= right; i++) arr[top][i] = num++;    // 向右填充
        top++;

        for (int i = top; i <= bottom; i++) arr[i][right] = num++;  // 向下填充
        right--;

        for (int i = right; i >= left; i--) arr[bottom][i] = num++; // 向左填充
        bottom--;

        for (int i = bottom; i >= top; i--) arr[i][left] = num++;   // 向上填充
        left++;
    }

    return arr;
}

6、更多题目

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

窗口大小不固定,当前无重复字符的时候应该扩展窗口

public int lengthOfLongestSubstring(String s) {
    int l = 0, r = -1;         // [0 ... r] 是滑动窗口
    int[] freq = new int[256]; // freq[c] = 滑动窗口中字符 c 的频率
    int res = 0;

    // 窗口的左边界在字符串范围内, 则循环继续
    while (l < s.length()) {
        if (r + 1 < s.length() && freq[s.charAt(r + 1)] == 0) freq[s.charAt(++r)]++;
        else freq[s.charAt(l++)]--;

        res = Math.max(res, r - l + 1);
    }

    return res;
}

438 - 找到字符串中所有字母异位词

窗口大小固定

public List<Integer> findAnagrams(String s, String p) {
    List<Integer> res = new LinkedList<>();
    if (s.length() < p.length()) return res;

    int[] freq_p = new int[26];   // freq_p 目标频率
    for (char c : p.toCharArray()) freq_p[c - 'a']++;

    int l = 0, r = p.length() - 1; // [l ... r] 是滑动窗口
    int[] freq_s = new int[26];    // freq_s[c] = 滑动窗口中字符 c 的频率

    for (int i = 0; i < p.length(); i++) freq_s[s.charAt(i) - 'a']++;
    if (same(freq_p, freq_s)) res.add(0);

    while (true) {
        if (r == s.length() - 1) break;

        r++;
        freq_s[s.charAt(r) - 'a']++;
        freq_s[s.charAt(l) - 'a']--;
        l++;
        if (same(freq_p, freq_s)) res.add(l);
    }

    return res;
}

private boolean same(int[] freq_p, int[] freq_s) {
    for (int i = 0; i < 26; i++) {
        if (freq_p[i] != freq_s[i]) return false;
    }
    return true;
}

76 - 最小覆盖子串

窗口大小不固定,还没覆盖完目标的时候应该扩展窗口

public String minWindow(String s, String t) {
    if (s.length() < t.length()) return "";

    // 目标
    int[] freq_t = new int[256];
    for (char c : t.toCharArray()) freq_t[c]++;

    // 窗口 [l ... r]
    int l = 0, r = -1;
    int[] freq_s = new int[256];
    int count = 0; // 窗口中包含 t 中字符的数量

    int startIndex = -1;
    int minLength = s.length() + 1;

    while (l < s.length()) {
        if (r + 1 < s.length() && count < t.length()) {
            r++;
            char c = s.charAt(r);
            freq_s[c]++;
            if (freq_s[c] <= freq_t[c]) count++;
        } else {
            char c = s.charAt(l);
            l++;
            freq_s[c]--;
            if (freq_s[c] < freq_t[c]) count--;
        }

        if (count == t.length() && r - l + 1 < minLength) {
            startIndex = l;
            minLength = r - l + 1;
        }
    }

    if (startIndex == -1) return "";
    return s.substring(startIndex, startIndex + minLength);
}
posted @ 2023-05-29 15:39  lidongdongdong~  阅读(17)  评论(0编辑  收藏  举报