TreeviewCopyright © qgao 2021-* all right reserved, powered by aleen42

其它技巧

最长回文子串

少有的动态规划非最优解法的问题。

String longestPalindrome(String s) {
    String res;
    for (int i = 0; i < s.size(); i++) {
        String s1 = palindrome(s, i, i);
        //返回以s[l]和s[r]为中心的最长回文串
        String s2 = palindrome(s, i, i + 1);
        // res = longest(res, s1, s2)  
        res = res.size() > s1.size() ? res : s1;
        res = res.size() > s2.size() ? res : s2;
    }
    return res;
}

前缀和数组

如何快速得到某个⼦数组的和,主要适用的场景是原始数组不会被修改的情况下,频繁查询某个区间的累加和。

int subarraySum(int[] nums, int k) {
    int n = nums.length;
    // map:前缀和 -> 该前缀和出现的次数  
    HashMap<Integer, Integer> preSum = new HashMap<>();
    // base case  
    preSum.put(0, 1);
    int ans = 0, sum0_i = 0;
    for (int i = 0; i < n; i++) {
        sum0_i += nums[i];
        // 这是我们想找的前缀和 nums[0..j]  
        int sum0_j = sum0_i - k;
        // 如果前⾯有这个前缀和,则直接更新答案  
        if (preSum.containsKey(sum0_j))  
            ans += preSum.get(sum0_j);
        // 把前缀和 nums[0..i] 加⼊并记录出现次数  
        preSum.put(sum0_i,  
            preSum.getOrDefault(sum0_i, 0) + 1);
    }
    return ans;
}

差分数组

主要适用场景是频繁对原始数组的某个区间的元素进行增减。 比如说,我给你输入一个数组nums,然后又要求给区间nums[2..6]全部加 1,再给nums[3..9]全部减 3,再给nums[0..4]全部加 2,再给… 一通操作猛如虎,然后问你,最后nums数组的值是什么? 构造一个diff差分数组:diff[i]=nums[i]-nums[i-1] diff差分数组反推原始数组nums:nums[i]=nums[i-1]+diff[i]

int[] nums = new int[diff.length];
// 根据差分数组反推结果数组  
nums[0] = diff[0];
for (int i = 1; i < diff.length; i++) {
    nums[i] = nums[i - 1] + diff[i];
}

如果你想对区间nums[i..j]的元素全部加 3,那么只需要让diff[i] += 3,然后再让diff[j+1] -= 3即可:

diff[i] += val;
if (j + 1 < diff.length) {
    diff[j + 1] -= val;
}

【力扣第 1109 题】「航班预订统计」

int[] corpFlightBookings(int[][] bookings, int n) {
    // nums 初始化为全 0  
    int[] nums = new int[n];
    // 构造差分解法  
    Difference df = new Difference(nums);
    for (int[] booking : bookings) {
        // 注意转成数组索引要减一哦  
        int i = booking[0] - 1;
        int j = booking[1] - 1;
        int val = booking[2];
        // 对区间 nums[i..j] 增加 val  
        df.increment(i, j, val);
    }
    // 返回最终的结果数组  
    return df.result();
}

2Sum

vector<vector<int>> twoSumTarget(vector<int>& nums, int target) {
    // nums 数组必须有序  
    sort(nums.begin(), nums.end());
    int lo = 0, hi = nums.size() - 1;
    vector<vector<int>> res;
    while (lo < hi) {
        int sum = nums[lo] + nums[hi];
        int left = nums[lo], right = nums[hi];
        if (sum < target) {
            while (lo < hi && nums[lo] == left) lo++;
        } else if (sum > target) {
            while (lo < hi && nums[hi] == right) hi--;
        } else {
            res.push_back({
                left, right
            }
            );
            while (lo < hi && nums[lo] == left) lo++;
            while (lo < hi && nums[hi] == right) hi--;
        }
    }
    return res;
}

田忌赛马

\870. 优势洗牌 打得过就打,打不过就拿自己的垃圾和对方的精锐互换。 根据这个思路,我们需要对两个数组排序,但是nums2中元素的顺序不能改变,因为计算结果的顺序依赖nums2的顺序,所以不能直接对nums2进行排序,而是利用其他数据结构来辅助。

int[] advantageCount(int[] nums1, int[] nums2) {
    int n = nums1.length;
    // 给 nums2 降序排序  
    PriorityQueue<int[]> maxpq = new PriorityQueue<>(  
        (int[] pair1, int[] pair2) -> {
        return pair2[1] - pair1[1];
    });
    for (int i = 0; i < n; i++) {
        maxpq.offer(new int[]{i, nums2[i]});
    }
    // 给 nums1 升序排序  
    Arrays.sort(nums1);
    // nums1[left] 是最小值,nums1[right] 是最大值  
    int left = 0, right = n - 1;
    int[] res = new int[n];
    while (!maxpq.isEmpty()) {
        int[] pair = maxpq.poll();
        // maxval 是 nums2 中的最大值,i 是对应索引  
        int i = pair[0], maxval = pair[1];
        if (maxval < nums1[right]) {
            // 如果 nums1[right] 能胜过 maxval,那就自己上  
            res[i] = nums1[right];
            right--;
        } else {
            // 否则用最小值混一下,养精蓄锐  
            res[i] = nums1[left];
            left++;
        }
    }
    return res;
}
Copyright © qgao 2021-* all right reserved,powered by Gitbook该文件修订时间: 2022-07-08 12:24:46

results matching ""

    No results matching ""