【Golang】LeetCode面试经典150题:移除元素

题干:

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素。元素的顺序可能发生改变。然后返回 nums 中与 val 不同的元素的数量。

假设 nums 中不等于 val 的元素数量为 k,要通过此题,您需要执行以下操作:

  • 更改 nums 数组,使 nums 的前 k 个元素包含不等于 val 的元素。nums 的其余元素和 nums 的大小并不重要。
  • 返回 k

解法1:双指针,没有心智负担

        解法1其实就是把不同的元素复制进新数组再返回新数组长度

解析1:

  1. 初始化两个指针:i 和 ki 用于遍历数组,k 用于记录不等于 val 的元素的位置。
  2. 遍历数组 nums,对于每个元素 nums[i]
    • 如果 nums[i] 不等于 val,将其赋值给 nums[k],并将 k 增加 1。
  3. 遍历结束后,k 的值就是不等于 val 的元素的数量。
  4. 返回 k
func removeElement(nums []int, val int) int {
    k := 0
    for i := 0; i < len(nums); i++ {
        if nums[i] != val {
            nums[k] = nums[i]
            k++
        }
    }
    return k
}

示例:

假设 nums = [3, 2, 2, 3]val = 3,执行上述代码的过程如下:

  1. 初始状态:i = 0k = 0nums = [3, 2, 2, 3]
  2. 遍历到 nums[0] = 3,不满足条件,跳过。
  3. 遍历到 nums[1] = 2,满足条件,nums[k] = 2k++nums = [2, 2, 2, 3]
  4. 遍历到 nums[2] = 2,满足条件,nums[k] = 2k++nums = [2, 2, 2, 3]
  5. 遍历到 nums[3] = 3,不满足条件,跳过。
  6. 遍历结束,k = 2nums = [2, 2, 2, 3]

最终返回 k = 2nums 的前两个元素为 [2, 2],符合题目要求

复杂度分析:

  • 时间复杂度:O(n),其中 n 是数组的长度。每个元素最多被访问一次。
  • 空间复杂度:O(1),只使用了常数级别的额外空间。

解法2:双指针优化(官方出题的真正意图)

        题目只要求返回不同的数量k,这个优化算法是首尾双指针,头指针遍历数组,遇到val就用尾指针元素替换val,然后左移尾指针的位置。这个替换操作的同时,也缩短了需要遍历数组的长度,直到首尾指针重合,输出头指针遍历过的长度就行。

        注意,如果替换过来的尾指针依然是val,需要再次替换尾指针元素,尾指针左移。说白了就是,不能替换完尾指针就右移头指针,因为还没判断尾指针的值

        优点当 val 在数组中出现较少时,可以减少元素的移动次数,从而提高效率。

解析2:

  1. 初始化两个指针:left 和 rightleft 从数组的起始位置开始,right 从数组的末尾位置开始。
  2. 遍历数组 nums,条件是 left < right
    • 如果 nums[left] 等于 val,将 nums[right-1] 的值赋给 nums[left],并将 right 减少 1。
    • 如果 nums[left] 不等于 val,将 left 增加 1。
  3. 遍历结束后,left 的值就是不等于 val 的元素的数量。
  4. 返回 left
func removeElement(nums []int, val int) int {
    left, right := 0, len(nums)
    for left < right {
        if nums[left] == val {
            nums[left] = nums[right-1]
            right--
        } else {
            left++
        }
    }
    return left
}

示例:

假设 nums = [3, 2, 2, 3]val = 3,执行上述代码的过程如下:

  1. 初始状态:left = 0right = 4nums = [3, 2, 2, 3]
  2. 遍历到 nums[0] = 3,满足条件,nums[0] = nums[3]right--nums = [3, 2, 2, 3]
  3. 遍历到 nums[0] = 3,满足条件,nums[0] = nums[2]right--nums = [2, 2, 2, 3]
  4. 遍历到 nums[0] = 2,不满足条件,left++nums = [2, 2, 2, 3]
  5. 遍历到 nums[1] = 2,不满足条件,left++nums = [2, 2, 2, 3]
  6. 遍历结束,left = 2nums = [2, 2, 2, 3]

最终返回 left = 2nums 的前两个元素为 [2, 2],符合题目要求。

复杂度分析:

  • 时间复杂度:O(n),其中 n 是数组的长度。每个元素最多被访问一次。
  • 空间复杂度:O(1),只使用了常数级别的额外空间。

你可能感兴趣的:(【go】力扣面试经典150题,leetcode,面试,算法,golang,数据结构)