【每日算法0223】双指针(简单)

99 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 15 天,点击查看活动详情

题目

剑指 Offer 21. 调整数组顺序使奇数位于偶数前面

输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数在数组的前半部分,所有偶数在数组的后半部分。

示例:

输入:nums = [1,2,3,4]
输出:[1,3,2,4] 
注:[3,1,2,4] 也是正确的答案之一。

分析

使用快慢指针,动态交换边界点值的位置

  • 快指针遍历整个数组
  • 遍历过程中,针对奇数值做处理

如果遇到偶数,慢指针不动,快指针继续遍历

如果遇到奇数,慢指针前移,由于慢指针始终处于边界处,会指向一个偶数值,需要交还给当前的奇数值,按此迭代下去

  • 最后返回原数组

实现

var exchange = function(nums) {
    let fast = 0
    let slow = - 1
​
    while (fast < nums.length) {
        let cur = nums[fast]
        if (isOdd(cur)) {
            slow ++
            [nums[fast], nums[slow]] = [nums[slow], cur]
        }
        fast ++
    }
​
    function isOdd (val) {
        return val%2 !== 0
    }
​
    return nums
};

题目

剑指 Offer 57. 和为s的两个数字

输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s。如果有多对数字的和等于s,则输出任意一对即可。

示例:

输入:nums = [2,7,11,15], target = 9
输出:[2,7] 或者 [7,2]

分析一

本题可以利用一些数学的思维求解

利用哈希表方法,在遍历时,求出每个值相对应的差值,存储起来

并且同时判断当前值是不是在哈希表中,如果存在该值,就返回但前值和上一个值(上一个值可以用目标值减当前值反向得出)

实现

function twoSum(nums: number[], target: number): number[] {
    let map: Map<number, null> = new Map()
    for (let i = 0; i < nums.length; i++) {
        if (map.has(nums[i])) {
            return [target - nums[i], nums[i]]
        } else {
            map.set(target - nums[i], null)
        }
    }
};

分析二

因为该数组有序,可以使用双指针对撞遍历得出

  • 定义首尾端点
  • 遍历数组,当端点相遇时结束
  • 使用某一端点计算差值对比

以左端点为例子(左端点为最小值),每次同时求出与目标值的差值

那么符合要求的点肯定在最右边

这时需要判断右侧的点,如果差值大于右端点的值,说明不存在符合当前最小值相对应的点,左端点右移

如果差值小于右端点的值,说明当前右端点的值无法找到与之对应的左端点,右端点左移

当差值为 0 时,返回这两个点

实现

function twoSum(nums: number[], target: number): number[] {
    let left = 0
    let right = nums.length - 1
    while (left < right) {
        let dif = target - nums[left]
        if (dif > nums[right]) {
            left ++
        } else if (dif < nums[right]) {
            right --
        } else {
            return [nums[left], nums[right]]
        }
    }
};