每日算法题3 ——调整数组顺序使奇数位于偶数前、和为s的三个连续整数、和为s的连续整数序列

141 阅读1分钟

调整数组顺序

剑指 Offer 21. 调整数组顺序使奇数位于偶数前面 - 力扣(LeetCode)

方法一:双指针

思路:

设定两个指针,第一个指针left从数组第一个元素出发,向尾部前进,如果遇到的是奇数,说明该元素已调整好,继续向右遍历,直到遇到一个偶数;第二个指针right从数组的最后一个元素出发,向头部前进,直到遍历到奇数时,交换两个数的位置

var exchange = function(nums) {
    let left = 0, right = nums.length -1
    while(left < right) {
        while(left < right && nums[left] % 2 === 1) {
            left++
        }
        while(left < right && nums[right] % 2 === 0) {
            right--
        }
        if(left < right) {
            //交换
            [nums[left], nums[right]] = [nums[right], nums[left]]
            left++
            right--
        }
    }
    return nums
};
  • 时间复杂度: O(n),只遍历一次
  • 空间复杂度: O(1)

方法二:双指针+一次遍历

思路: 新建一个保存结果的数组,长度为nums的长度,遍历nums,遇到奇数则从res的左侧开始替换元素,遇到偶数就从res的右侧替换元素。

var exchange = function(nums) {
    let res = new Array(nums.length).fill(0)
    let left = 0, right = nums.length -1
    for(let num of nums) {
        if(num % 2 !== 0) {
            res[left++] = num
        }else {
            res[right--] = num
        }
    }
    return res
};
  • 时间复杂度: O(n),只遍历一次
  • 空间复杂度: O(1),结果不计入空间复杂度

方法三:两次遍历

新建一个数组 res 用来保存调整完成的数组。遍历两次nums,第一次遍历时把所有奇数依次追加到 res 中,第二次遍历时把所有偶数依次追加到res 中。

移除元素

移除元素 - 移除元素 - 力扣(LeetCode)

题目描述:给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

方法: 双指针法

思路:使用快慢指针,慢指针指向将要赋值的位置,快指针指向将要进行处理的元素

如果快指针指向的元素不等于 val,它一定是输出数组的一个元素,我们就将快指针指向的元素复制到慢指针位置,然后将快慢指针同时右移;

如果右指针指向的元素等于val,它不能在输出数组里,此时慢指针不动,快指针右移一位。

整个过程保持不变的性质是:区间[0,left) 中的元素都不等于val。当快慢指针遍历完输入数组以后,left 的值就是输出数组的长度。

这样的算法在最坏情况下(输入数组中没有元素等于val),快慢指针各遍历了数组一次

代码实现

var removeElement = function(nums, val) {
    let left = 0
    for(let right = 0; right < nums.length; right++) {
        if(nums[right] !== val) {
            nums[left] = nums[right]
            left++
        } 
    }
    return left
};
  • 时间复杂度: O(n),只需要遍历该序列至多两次
  • 空间复杂度: O(1)

注意:不能使用排序数组的双指针法,因为当输入数组的元素全为目标值,需要删除时,就会出错

//下面这种写法不能通过全部样例
var removeElement = function(nums, val) {
    let left = 0, right = nums.length - 1
    while(left < right) {
        while(left < right && nums[left] !== val) {
            left++
        }
        while(left < right && nums[right] === val) {
            right--
        }
        if(left < right) {
            [nums[left], nums[right]] = [nums[right], nums[left]]
            left++
            right--
        }
    }
    return left + 1
};

找到和为给定整数的三个连续整数

2177. 找到和为给定整数的三个连续整数 - 力扣(LeetCode)

题目描述

给一个整数num,返回三个连续的整数,它们的和为num,如果num无法被表示成三个连续整数的和,返回一个空数组。

var sumOfThree = function(num) {
    if(num % 3 === 0) {
        return [num / 3 -1, num/3, num/3+1]
    }
    return []
};
  • 时间复杂度: O(1)
  • 空间复杂度: O(1)

和为s的连续正整数序列

剑指 Offer 57 - II. 和为s的连续正数序列 - 力扣(LeetCode)

题目: 输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数)。序列内的数字由小到大排列,不同序列按照首个数字从小到大排列。

例如:输入15,有序1+2+3+4+5 = 4+5+6 = 7+8 = 15 所以打印出3个连续序列1-55-67-8

var findContinuousSequence = function(target) {
    let res = []
    let tmp = [1,2]  //窗口
    let l = 1, r = 2
    let sum = 3
    while(r < target) {
        while(sum < target && r < target) {
            tmp.push(++r)
            sum += r 
        }
        while(sum > target && l < r) {
            tmp.shift()
            sum -= l
            l++
             
        }
        if(sum === target && tmp.length > 1) {
            res.push(tmp.slice())
            tmp.shift()
            sum -= l
            l++
            
        } 
    }
    return res
};