🎨每日面试算法题---腾讯篇(四)

343 阅读1分钟

三元素和双指针

这里指的是解决三个元素关系中的一种方法:通过创建特殊环境来使用双指针来降低问题复杂度

相关题目

三数之和 - 力扣(LeetCode) (leetcode-cn.com)

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List list = new ArrayList<ArrayList<Integer>>();
        Arrays.sort(nums);
        if (nums.length < 3) return list;
        int l, r;
        for (int i = 0; i < nums.length - 2; i++) {
            l = i + 1;
            r = nums.length - 1;
            while (l < r) {
                if(nums[l] + nums[r] == -nums[i]) {
                    list.add(Arrays.asList(nums[l], nums[r], nums[i]));
                    while (nums[l] == nums[l + 1] && l + 1 < r) l++;
                    while (nums[r] == nums[r - 1] && r - 1 > l) r--;
                    l++;
                    r--;
                }
                else if(nums[l] + nums[r] < -nums[i]) l++;
                else r--;
            }
            while (i < nums.length - 2 && nums[i + 1] == nums[i]) i++;
        }
        return list;
    }
}

最接近的三数之和 - 力扣(LeetCode) (leetcode-cn.com)

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number}
 */
var threeSumClosest = function(nums, target) {
    nums.sort((a, b) => a - b)
    let l,r,ans = nums[0] + nums[1] + nums[2]; 
    for(let i = 0; i < nums.length - 2; i++) {
        l = i + 1, r = nums.length - 1;
        while(l < r) {
            ans = Math.abs(ans - target) > Math.abs(nums[l] + nums[r] + nums[i] - target) ? nums[l] + nums[r] + nums[i] : ans
            if(nums[l] + nums[r] + nums[i] === target) return target
            else if(nums[l] + nums[r] + nums[i] < target) l++ 
            else r--
        }
    }
    return ans
}

这两道题的共通点在于他们都是在找寻三个数的某种关系(这里都是和)。比如上面的题,如果我们从一个序列中直接寻找三个数之间的和的关系,那么显而易见,需要循环三层,其复杂度是O(N^3)。

但是我们如果对这类题加以剖析,我们可以发现将序列变为一个有一定规律的序列(大部分都可以排序解决)后,就可以对一个数先进行一层循环,然后第二层循环就是另外两个数(双指针),同时在数列中由于三个元素之间是有关系的(第一题是和为某个值,第二题是和接近某个值),而且这个序列也是有规律的,所以我们可以直接通过三个数之间的现状来直接调整双指针的位置,从而只进行两层循环了。复杂度减低到O(N^2)

这体现出来从题目的数据中找到合适的关系,通过创造合适的环境,让时间复杂度下降的一种思维方式。