Go语言入门指南:数组篇|青训营

60 阅读2分钟

数组是非常基础的数据结构,也是GO语言基本语法的重要组成部分。数组习题的思维并不复杂,在编写代码时却遇到了不少问题。本篇将重点放在代码编写上。

习题出自力扣,相关思路、代码出自代码随想录。

1.二分查找

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target  ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。

非常经典的一道题,将有序区间不断二分,直至找到目标。

思路可大致分为两种:1.左闭右闭区间 2.左闭右开区间

我更喜欢第一种,因而使用第一种代码进行记录

func search(nums []int, target int) int {
    high := len(nums)-1
    low := 0
    for low <= high {
        mid := low + (high-low)/2
        if nums[mid] == target {
            return mid
        } else if nums[mid] > target {
            high = mid-1
        } else {
            low = mid+1
        }
    }
    return -1
}

思路如下:设置左右两个指针指向区间的上限、下限,一个变量mid用于循环改变变量,

若nums[mid]==target:返回mid//题目要求是返回数组下标

若nums[mid]>target:上限high左移//此处high=mid-1,因为nums[mid]一定不是target

若nums[mid]<target:下限low右移//此处low=mid+1,同理

这个题的难点在于区间的划分,即是否要取等号,是否要mid+1或mid-1

2.移除元素

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

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

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

思路:1.两层for循环 2.双指针法(近似于第一题的第一种解法) 双指针法:类似于快速排序的坑位法

func removeElement(nums []int, val int) int {
    // 有点像二分查找的左闭右闭区间 所以下面是<=
	left := 0
	right := len(nums) - 1
	for left <= right {
		// 不断寻找左侧的val和右侧的非val 找到时交换位置 目的是将val全覆盖掉
		for left <= right && nums[left] != val {
			left++
		}
		for left <= right && nums[right] == val {
			right--
		}
		//各自找到后开始覆盖 覆盖后继续寻找
		if left < right {
			nums[left] = nums[right]
			left++
			right--
		}
	}
	fmt.Println(nums)
	return left
}

3.有序数组的平方

给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。

思路:1.平方后使用sort排序 2.双指针法(又来了)

题外话:这道题我开始的时候审题有误,理解成除了非递减顺序以外的排序:递增和无序 写完了才发现不对劲哈哈哈

func sortedSquares(nums []int) []int {
	n := len(nums)
	i, j, k := 0, n-1, n-1
	ans := make([]int, n) //建立一个与nums等长的新数组
	for i <= j {
		lm, rm := nums[i]*nums[i], nums[j]*nums[j]
		if lm > rm {
			ans[k] = lm
			i++
		} else {
			ans[k] = rm
			j--
		}
		k--
	}
	return ans
}

给定的nums是有序数组,因而并不会出现左边大于右边的情况。

4.长度最小的子数组

给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。

思路:1.两层for循环(万金油,然而时间复杂度不符合要求)

2.滑动窗口

所谓滑动窗口,就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果

在本题中,使用一个for循环表示滑动窗口的结束位置,需要确定如下三点:

  • 窗口内是什么?
  • 如何移动窗口的起始位置?
  • 如何移动窗口的结束位置?
func minSubArrayLen(target int, nums []int) int {
    i := 0
    l := len(nums)  // 数组长度
    sum := 0        // 子数组之和
    result := l + 1 // 初始化返回长度为l+1,目的是为了判断“不存在符合条件的子数组,返回0”的情况
    for j := 0; j < l; j++ {
        sum += nums[j]
        for sum >= target {
            subLength := j - i + 1
            if subLength < result {
                result = subLength
            }
            sum -= nums[i]
            i++
        }
    }
    if result == l+1 {
        return 0
    } else {
        return result
    }
}