9.1 学习

99 阅读5分钟

9.1完成任务

1、Leetcode算法题把数组部分刷完了,明天开始链表部分。(其实数组部分的方法要么就考察数学思想,要么双指针,要么滑动窗口,不难)

2、综设课上,对serverless有了一定基础的了解,接下来的两周估计还要学一下这方面的知识

3、go语言之旅的基础又过完了一遍,明天可以开始过包、变量和函数了

4、早上开摆了,没听听力,悲

代码随想录 --数组(二分查找)

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

示例 1:

输入: nums = [-1,0,3,5,9,12], target = 9 输出: 4 解释: 9 出现在 nums 中并且下标为 4

示例 2:

输入: nums = [-1,0,3,5,9,12], target = 2 输出: -1 解释: 2 不存在 nums 中因此返回 -1

for range 相关

首先来个例题方便理解。

package main

import "fmt"

func main() {
	map1 := make(map[int]float32)
	map1[1] = 1.0
	map1[2] = 2.0
	map1[3] = 3.0
	map1[4] = 4.0

	// 读取 key 和 value
	for key, value := range map1 {
		fmt.Printf("key is: %d - value is: %f\n", key, value)
	}

	// 读取 key
	for key := range map1 {
		fmt.Printf("key is: %d\n", key)
	}

	// 读取 value
	for _, value := range map1 {
		fmt.Printf("value is: %f\n", value)
	}
}

这段代码是在菜鸟教程上面看到的,说输出是

key is: 4 - value is: 4.000000
key is: 1 - value is: 1.000000
key is: 2 - value is: 2.000000
key is: 3 - value is: 3.000000
key is: 1
key is: 2
key is: 3
key is: 4
value is: 1.000000
value is: 2.000000
value is: 3.000000
value is: 4.000000

嘶,开始好奇,为啥前面的key不是按1234来排序的呢。

于是在自己的goland上面复制代码跑了一下,

image.png

重复跑了几次,没有一次有相同的结果。

原因是什么呢?

在 Go 中,map 是一个无序的数据结构,这意味着 map 中的键值对没有固定的顺序。因此,当迭代一个 map 时,不能保证迭代的顺序会是相同的。这就是每次运行都得到不同答案的原因。

尽管添加键值对的顺序是固定的(1、2、3、4),但在 map 内部,这些键值对的存储和迭代顺序是不确定的。因此,第一个 for 循环中的键值对可能会以不同的顺序出现,导致不同的输出结果。

原来是map的原因哇。所以想要按照顺序来进行排序,必须首先将键(或值)排序,然后再进行迭代。

代码如下:

package main

import (
	"fmt"
	"sort"
)

func main() {
	map1 := make(map[int]float32)
	map1[1] = 1.0
	map1[2] = 2.0
	map1[3] = 3.0
	map1[4] = 4.0

	// 获取所有键并排序
	keys := make([]int, 0, len(map1))
	for key := range map1 {
		keys = append(keys, key)
	}
	sort.Ints(keys)

	// 按键的升序顺序迭代 map
	for _, key := range keys {
		value := map1[key]
		fmt.Printf("key is: %d - value is: %f\n", key, value)
	}
}

咳咳,扯远了,到map有关的了。

回到for range来

当使用 for range 迭代一个切片时,range 返回两个值:索引和元素值。如果希望查找目标值并返回其索引。可以使用 for range 迭代切片,但要注意 for range 中的索引是数组的索引,而不是数组的值。

代码如下:

func search(nums []int, target int) int {
    for i,num :=range nums{//此时i代表的是所对应值的索引,num代表的是元素值
        if num==target{
            return i
        }
    }
    return -1
}

显然可以发现 nums[i]=num, 所以也可以写成如下形式

func search(nums []int, target int) int {
    for i,_ :=range nums{
        if nums[i]==target{
            return i
        }
    }
    return -1
}

OK,现在for range 弄清楚了,回到题目中来,此题好歹也是一个二分查找,直接遍历找完也太蠢了。

二分查找

实现代码如下,大概思想就是,设头尾俩个指针,然后由于数组已经升序处理了,就取中间数查看与目标数的大小关系,如果小,就把该数左边的数设为右指针。大,同理

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

代码随想录 --数组(有序数组的平方)

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

示例 1:

输入:nums = [-4,-1,0,3,10] 输出:[0,1,9,16,100] 解释:平方后,数组变为 [16,1,0,9,100] 排序后,数组变为 [0,1,9,16,100]

示例 2:

输入:nums = [-7,-3,2,3,11] 输出:[4,9,9,49,121]

思路

拿到此题,首先想到的就是创造一个新数组来存储这些平方后的元素,然后再使用排序算法来进行排序即可。(此种方法时间复杂度挺高的)

代码如下:

func sortedSquares(nums []int) []int {
    news := make([]int,len(nums))
    for i,_ := range nums{
        news[i]=nums[i]*nums[i]
    }
    sort.Ints(news)

    return news
}

但是呢,很明显有着效率更高的解决方法。 首先最大的平方值肯定是在两侧找到,最小的平方值肯定在中间。此题我们就先用最大往里面找吧。最大的就放在新数组最后面。

代码如下

func sortedSquares(nums []int) []int {
    news := make([]int,len(nums))
    left :=0
    right :=len(nums)-1
    i :=len(nums)
    for left<=right{
        if nums[left]*nums[left]>=nums[right]*nums[right]{
            news[i-1]=nums[left]*nums[left]
            left++
            i--
        }else{
            news[i-1]=nums[right]*nums[right]
            right--
            i--
        }
    }

    return news
}

题目很简单。看了题解和我的方法一样,继续~

代码随想录 --数组(长度最小的子数组)

给定一个含有 n 个正整数的数组和一个正整数 target 。

找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。

示例 1:

输入:target = 7, nums = [2,3,1,2,4,3] 输出:2 解释:子数组 [4,3] 是该条件下的长度最小的子数组。

示例 2:

输入:target = 4, nums = [1,4,4] 输出:1

示例 3:

输入:target = 11, nums = [1,1,1,1,1,1,1,1] 输出:0

思路

本来第一眼看到最少以为是要贪心,然后发现题目要求连续,看来是滑动窗口。

代码如下:

func minSubArrayLen(target int, nums []int) int {
    left := 0
    right :=len(nums)
    sum:=0
    length := right+1
    for i:=0;i<len(nums);i++{
        sum+=nums[i]
        for sum>=target{
            sublength := i-left+1
            if sublength<length{
                length=sublength
            }
            sum-=nums[left]
            left++
        }

    }
    if length== right+1{
        return 0
    }else{
        return length
    }
}

可以理解为左右指针中间窗口的sum为两指针的“共同财产”,就是右指针一直在努力工作挣钱,好不容易共同财产大过target,记录一下两指针之间的距离,结果左指针就开始得瑟挥霍,不停花钱(往右移动),结果花钱一直花到sum又小过target,此时右指针不得不再次出来工作,不停向右移动,周而复始,最后取左右指针离得最近的时候。

做的此种方法复杂度是最低的,就没有再细看官方的解答了。

代码随想录 --数组(螺旋矩阵II)

数组专栏里面最后一题~~

给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。

示例 1:

image.png

输入:n = 3 输出:[[1,2,3],[8,9,4],[7,6,5]]

示例 2: 输入:n = 1 输出:[[1]]

思路

有一说一,刚拿到题,确实懵掉了(主要没想起来go语言的二维数组咋写,C语言到知道)

然后就先考虑怎么实现把。

第一个例题的图其实可以用来进行拆分。首先将1,2放在一起 34放在一起等等 (其实就是每一个方向n-1个数)。这样保证每一个方向的数的个数是相同的。然后最外面一层走完以后,到里面 其实就是一个方向还剩下n-2个数。

思路差不多理清楚了(这样对边界的判断会好写一点)

然后就是代码实现。

首先肯定要设置四个变量代表上下左右。分别设为0,n-1,0,n-1。然后设置一个num,来统计我们填了多少个数,以及一个max,设置为需要填写的数的个数。以及最后还有一个二维数组array来存储数据

代码如下:

func generateMatrix(n int) [][]int {
    top, bottom := 0, n-1
    left, right := 0, n-1
    max := n * n
    num :=1
    array := make([][]int, n)
    for i := 0; i < n; i++ {
        array[i] = make([]int, n)
    }
    
    for num <= max {
        for i := left; i <= right; i++ {
            array[top][i] = num
            num++
        }
        top++//其实就是最上面往里面缩了一行
        for i := top; i <= bottom; i++ {
            array[i][right] = num
            num++
        }
        right--
        for i := right; i >= left; i-- {
            array[bottom][i] = num
            num++
        }
        bottom--
        for i := bottom; i >= top; i-- {
            array[i][left] = num
            num++
        }
        left++
    }
    return array
}

代码解释: 这一块是二维数组的初始化!,真忘了,得多用用。

    array := make([][]int, n)
    for i := 0; i < n; i++ {
        array[i] = make([]int, n)
    }

总结

其实这个题目主要和数学思维有关吧,如果开始分类没分好,感觉会被边界判断折磨,其实整体代码实现并不难,主要是二维数组的初始化忘了,悲。