目的是通过写lc来提交对golang语法的熟悉程度

题目

344. 反转字符串

难度简单740

编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。

不要给另外的数组分配额外的空间,你必须**原地修改输入数组**、使用 O(1) 的额外空间解决这一问题。

本题比较简单, 需要注意的就是GO里面没有while关键字, 通过for来循环

1
2
3
4
5
6
7
8
9
func reverseString(s []byte)  {
i:=0
j:=len(s)-1
for i<j {
s[i],s[j]=s[j],s[i]
i++
j--
}
}

376. 摆动序列

难度中等889

如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为 **摆动序列 。**第一个差(如果存在的话)可能是正数或负数。仅有一个元素或者含两个不等元素的序列也视作摆动序列。

  • 例如, [1, 7, 4, 9, 2, 5] 是一个 摆动序列 ,因为差值 (6, -3, 5, -7, 3) 是正负交替出现的。
  • 相反,[1, 4, 7, 2, 5][1, 7, 4, 5, 5] 不是摆动序列,第一个序列是因为它的前两个差值都是正数,第二个序列是因为它的最后一个差值为零。

子序列 可以通过从原始序列中删除一些(也可以不删除)元素来获得,剩下的元素保持其原始顺序。

给你一个整数数组 nums ,返回 nums 中作为 摆动序列最长子序列的长度

本题的关键点在于题目的要求的是求序列的长度, 因此我们不需要统计全部, 只需要两个up , down变量分别统计 最后一个元素为上升/下降的序列的长度 ,

然后通过前一个变量来判断当前的元素应该放到升/降序列中 , 最后返回两个序列的最大长度即可

注意math.Max( ) 的参数为float64类型

1
2
3
4
5
6
7
8
9
10
11
12
func wiggleMaxLength(nums []int) int {
up := 1
down := 1
for i := 1; i < len(nums); i++ {
if nums[i-1] > nums[i] {
up = down + 1
} else if nums[i-1] < nums[i] {
down = up + 1
}
}
return int(math.Max(float64(up), float64(down)))
}

11. 盛最多水的容器

labuladong 题解思路

难度中等4205

给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0)(i, height[i])

找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

返回容器可以储存的最大水量。

**说明:**你不能倾斜容器。

解法

双指针, 从两边缩减 , 每次移动短板的那一边, 维护res返回即可

原本打算使用math.Max() , 但是go 的math包的方法的大多数参数类型都是float , 所以只能自己写一个

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
func maxArea(height []int)int {
res:=0
l, r := 0, len(height)-1
for l < r {
area := (r - l) * min(height[l], height[r])
res = max(res, area)
if height[l] < height[r] {
l++
} else {
r--
}
}
return res
}
func min(a, b int) int { if a > b { return b }; return a }
func max(a, b int) int { if a < b { return b }; return a }

12. 整数转罗马数字

难度中等1084

罗马数字包含以下七种字符: IVXLCDM

1
2
3
4
5
6
7
8
字符          数值
I 1
V 5
X 10
L 50
C 100
D 500
M 1000

例如, 罗马数字 2 写做 II ,即为两个并列的 1。12 写做 XII ,即为 X + II 。 27 写做 XXVII, 即为 XX + V + II

通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:

  • I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
  • X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。
  • C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。

给你一个整数,将其转为罗马数字。

解法

我们可以利用map来存储需要的数字, 注意题目给出的参数num的范围

提示:

  • 1 <= num <= 3999

那么我们最多只需要到1000 的字符 M

首先把数字对应的字符对应在map中 , 然后进行贪心 , 每次都减去当前数字能减去的最大的数字 , 然后追加字符串 , 最终返回即可

对于strs 的说明:

  • 对于(1,10)的数字 , 我们只需要知道I IV V 即可表示出全部的数字

    因为罗马数字对于 **4 以及 **9的表示方法是为10的当前位数幂次方减去指定的数组 , 比如 9 就是表示为IX , 其中X为10 , I为1 , 表示 X-I = 9

1
2
3
4
5
6
7
8
9
10
11
12
13
14
func intToRoman(num int) string {
vals := []int{1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1}
strs := []string{"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"}
res := ""
idx := 0
for num > 0 {
for num >= vals[idx] {
num -= vals[idx]
res += strs[idx]
}
idx++
}
return res
}

执行用时:12 ms, 在所有 Go 提交中击败了30.36%的用户

内存消耗:3 MB, 在所有 Go 提交中击败了78.57%的用户

下面再来看另一种哈希表的写法

来自题解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
var valueSymbols = []struct {
value int
symbol string
}{
{1000, "M"},
{900, "CM"},
{500, "D"},
{400, "CD"},
{100, "C"},
{90, "XC"},
{50, "L"},
{40, "XL"},
{10, "X"},
{9, "IX"},
{5, "V"},
{4, "IV"},
{1, "I"},
}

func intToRoman(num int) string {
roman := []byte{}
for _, vs := range valueSymbols {
for num >= vs.value {
num -= vs.value
roman = append(roman, vs.symbol...)
}
if num == 0 {
break
}
}
return string(roman)
}

执行用时:8 ms, 在所有 Go 提交中击败了62.09%的用户

内存消耗:3 MB, 在所有 Go 提交中击败了91.35%的用户

  • 如果只想取值,不需要索引,可以用"_"下划线占位索引。

通过对比发现第二次代码的执行效率更高是因为使用了append()方法

修改了第一次的代码,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
func intToRoman(num int) string {
vals := []int{1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1}
strs := []string{"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"}
// res := ""
res := []byte{}
idx := 0
for num > 0 {
for num >= vals[idx] {
num -= vals[idx]
res = append(res, strs[idx]...)
}
idx++
}
return string(res)
}

执行用时:8 ms, 在所有 Go 提交中击败了62.09%的用户

内存消耗:2.9 MB, 在所有 Go 提交中击败了94.92%的用户

发现执行耗时是一样的 , 实际上的时间提升来自于 使用了 append() , 相较于直接使用字符串相加, 效率更高

34. 在排序数组中查找元素的第一个和最后一个位置

labuladong 题解思路

难度中等2235

给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。

如果数组中不存在目标值 target,返回 [-1, -1]

你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
func searchRange(nums []int, target int) []int {
l, r := 0, len(nums)
for l < r {
m := l + (r-l)/2
if nums[m] < target {
l = m + 1
} else if nums[m] > target {
r = m
} else {
// 找到了
l = m
r = m
for l >= 0 && nums[l] == target {
l--
}
for r < len(nums) && nums[r] == target {
r++
}
return []int{l + 1, r - 1}
}
}
return []int{-1, -1}
}

121. 买卖股票的最佳时机

labuladong 题解思路

难度简单2897

给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。

你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。

返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
func maxProfit(prices []int) int {
res, cost := 0, prices[0]
for _, price := range prices {
res = max(res, price-cost)
cost = min(cost, price)
}
return res
}

func max(a int, b int) int {
if a > b {
return a
}
return b
}
func min(a int, b int) int {
if a > b {
return b
}
return a
}

79. 单词搜索

难度中等1563

给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false

单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。

需要注意的是如果需要在一个方法内部递归调用当前的方法, 并且这个方法的定义方式是 :=

比如下面的代码

这样是无法运行的

1
2
3
4
5
6
7
8
9
10
11
func main() {
var a func(s int)
a:= func(s int){
if s==100 {
return
}
fmt.Println(s)
a(s)
}
a(90)
}

可以看到编译器并不能找到我们定义的方法a

这个时候就需要提前的去声明func a() , 就像下面这样

1
2
3
4
5
6
7
8
9
10
11
func main() {
var a func(s int)
a= func(s int){
if s==100 {
return
}
fmt.Println(s)
a(s)
}
a(90)
}

回归原题, 本题的做法是使用递归 , 如果执行到当前的字符长度已经大于/等于word的长度 , 说明单词在board中 ,

代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
func exist(board [][]byte, word string) bool {
res := false
var dfs func(i, j, idx int)
dfs = func(i, j, idx int) {
if idx == len(word) || res {
res = true
return
}
if i < 0 || j < 0 || i >= len(board) || j >= len(board[0]) || board[i][j] != word[idx] {
return
}
board[i][j] ^= 255
dfs(i+1, j, idx+1)
dfs(i, j+1, idx+1)
dfs(i-1, j, idx+1)
dfs(i, j-1, idx+1)
board[i][j] ^= 255
}
for i := range board {
for j := range board[i] {
dfs(i, j, 0)
if res {
return res
}
}
}
return res
}

75. 颜色分类

难度中等1562

给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums ,**原地**对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。

我们使用整数 012 分别表示红色、白色和蓝色。

必须在不使用库内置的 sort 函数的情况下解决这个问题。

示例 1:

1
2
输入:nums = [2,0,2,1,1,0]
输出:[0,0,1,1,2,2]

示例 2:

1
2
输入:nums = [2,0,1]
输出:[0,1,2]

提示:

  • n == nums.length
  • 1 <= n <= 300
  • nums[i]012

通过读题 , 其实本题就是一个排序 , 特殊的一点就是需要排序的数组只有三种元素

解法

既然有三种元素, 那么我们可以维护三个指针, 把原来的数组分成三个分区

  • 0分区
  • 1分区
  • 2分区

由于数组需要排序, 因此当我们的0分区扩大的时候 指针1 2 都需要移动 , 同理在我们的分区1扩大的时候指针2需要移动, 而分区2扩大的时候则是只需要指针2移动即可

那么我们可以得到下面的代码

需要注意的是go 里面没有这样的写法nums[idx++]=1 , 虽然运算符中有++运算符 , 但是却不能使用这样的写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
func sortColors(nums []int)  {
idx1,idx2,idx0:=0,0,0
for _, i := range nums {
if i == 0 {
nums[idx2] = 2
nums[idx1] = 1
nums[idx0] = 0
} else if i == 1 {
nums[idx2] = 2
nums[idx1] = 1
idx0--
} else if i == 2 {
nums[idx2] = 2
idx1--
idx0--
}
idx0 += 1
idx1 += 1
idx2 += 1
}
}

84. 柱状图中最大的矩形 : 从暴力写法到单调栈优化

难度困难2387

给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。

求在该柱状图中,能够勾勒出来的矩形的最大面积。

示例 1:

1
2
3
输入:heights = [2,1,5,6,2,3]
输出:10
解释:最大的矩形为图中红色区域,面积为 10

示例 2:

1
2
输入: heights = [2,4]
输出: 4

提示:

  • 1 <= heights.length <=105
  • 0 <= heights[i] <= 104
暴力写法

我们遍历所有的矩形的高度 , 从当前的矩形向两边散开 , 然后维护一个最大值最后返回

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
func largestRectangleArea(heights []int) int {
res:=0
for i:= range heights{
res=max(getSize(heights,i),res)
}
return res
}
func getSize(heights []int , i int) int{
l,r:=i,i
for l>=0 && heights[l] >= heights[i]{
l--
}
for r<len(heights) && heights[r] >= heights[i]{
r++
}
return heights[i] * (r-l-1)
}
func max(a ,b int) int{
if a>b {
return a
}
return b
}

时间复杂度O(N2),外层循环 n 次,内层循环每次最多 n 次。

空间复杂度O(1)

单调栈优化

首先我们考虑一种特殊的情况, 就是每个柱子都是单调自增的 ,

那么此时对于每个柱子的左右边界也都是已知的 , 对于柱子 i , 他的左边界就是他自身 , 右边界就是最右边的那个最高的柱子 ( 如果右边没有柱子那么右边界也是他自身) ,

那么对应到代码里面 , 也就是 l=i, r=n-1 ; size= heigths[i] * (r-l+1)

1
2
l,r:=i,n-1
res=max(res,(r-l+1)*heights[i])

然后柱子是几乎不可能总是单调递增的 , 下面的这种情况更加符合一般情况

image-20230404131615345

对于上面的柱子, 当第五个柱子出现的时候, 此时的柱子不满足单调性 ,

那么对于第四个柱子来说 , 他的左右边界都是4 , 我们可以确定这个柱子能勾勒的最大的矩形面积是 5 ,

这个时候我们可以假装吧这个柱子 删除 ,

然后我们开始来计算第三个柱子可以勾勒的最大的矩形的面积 , 其实也就是下图中的红色区域的面积 , 计算的方式为 heights[2] * ( 3-2+1)

那么我们再假装删除 第三个柱子 , 对于第二个柱子 , 已经满足了单调性 , 因此我们继续计算即可

通过这样不断的进行遍历 , 计算, 我们维护一个最大的矩形面积最后返回即可

这里写的时候使用了两个哨兵 , 通过添加 哨兵 来减少代码量 , 取消多余的比较/判空

java代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Solution {
public int largestRectangleArea(int[] heights) {
int len = heights.length;
if(len==0) return 0;
if(len==1) return heights[0];
LinkedList<Integer> list = new LinkedList<>();
int res=0;
int[]newheights = new int[len+2]; // 新的数组, 添加哨兵, 在计算的时候不需要去判空 , 注意list 中的元素对应下标
newheights[0]=0;
newheights[len+1]=0;
// params: src start des start k
System.arraycopy(heights,0,newheights,1,len);
heights=newheights;
len+=2; // 更新数组的长度
list.addLast(0);
for(int i=1;i<len;i++){
while(heights[i] < heights[list.peekLast()]){
int curHeight = heights[list.pollLast()];
int curWidth = i - list.peekLast() - 1;
res = Math.max(res, curHeight * curWidth);
}
list.add(i);
}
return res;
}
}

go代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
func largestRectangleArea(heights []int) int {
len := len(heights)
if len == 0 {
return 0
}
if len == 1 {
return heights[0]
}
res := 0
l := list.New() // 创建一个List
newHeights := make([]int, len+2)
newHeights[0] = 0
newHeights[len+1] = 0
copy(newHeights[1:], heights) // 复制元素
heights = newHeights
len += 2
l.PushBack(0)
for i := 1; i < len; i++ {
for l.Len() > 0 && heights[i] < heights[l.Back().Value.(int)] {
h := heights[l.Remove(l.Back()).(int)]
w := i - l.Back().Value.(int) - 1
res = max(res, h*w)
}
l.PushBack(i)
}
return res
}

func max(a int, b int) int {
if a > b {
return a
}
return b
}

使用切片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
func largestRectangleArea(heights []int) int {
length := len(heights)
if length == 0 {
return 0
}
if length == 1 {
return heights[0]
}
res := 0
stack := make([]int, length)
newHeights := make([]int, length+2)
newHeights[0] = 0
newHeights[length+1] = 0
copy(newHeights[1:], heights) // 复制元素
heights = newHeights
length += 2
stack = append(stack, 0)
for i := 1; i < length; i++ {
for len(stack) > 1 && heights[i] < heights[stack[len(stack)-1]] {
h := heights[stack[len(stack)-1]] // 高度=> 前一个柱子的高度
stack = stack[:len(stack)-1] // 元素出栈
w := i - stack[len(stack)-1] - 1 // 计算宽
res = max(res, h*w)
}
stack = append(stack, i)
}
return res
}
func max(a int, b int) int {
if a > b {
return a
}
return b
}

1017. 负二进制转换

难度中等112

给你一个整数 n ,以二进制字符串的形式返回该整数的 **负二进制(base -2)**表示。

**注意,**除非字符串就是 "0",否则返回的字符串中不能含有前导零。

模拟

我们判断n从低位到高位的每一位, 如果当前位为1 ,

那么我们可以这样理解 ,

对于 二进制的11 结果为 3 , 对于 -2 进制的 11 , 结果为

111

在二进制的偶数位上,0或1的贡献和负二进制是一样的,只有在奇数位且为1时是相反的,如果在这里填了1,那么后面就需要补偿这个1。

因此算法中使用了一个奇偶变换的k,在正常二进制下这一位为1时,不论如何都做一步n=n-k,在奇偶位上作用是不同的,

在奇数时k是-1,相当于给n+1补偿了这一位的负数损失,

在偶数位上k是1,给n-1相当于把此时奇数的n变为了偶数,保证后续n/2时一定能没有余数,两种能统一成一行n=n-k还是挺优雅的,核心效果还是在奇数位。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
func baseNeg2(n int) string {
if n == 0 {
return "0"
}
res := []byte{}
k:=1
for n != 0 {
if n%2 != 0 {
res = append(res, '1')
n-=k
}else{
res = append(res, '0')
}
n/=2
k*=-1
}
for i, j := 0, len(res)-1; i < j; i, j = i+1, j-1 {
res[i], res[j] = res[j], res[i]
}
return string(res)
}

96. 不同的二叉搜索树

难度中等2202

给你一个整数 n ,求恰由 n 个节点组成且节点值从 1n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。

示例 1:

1
2
输入:n = 3
输出:5

示例 2:

1
2
输入:n = 1
输出:1

提示:

  • 1 <= n <= 19

我们考虑这样的思路 , 假设n个节点存在的BST的个数为G(n) , 以f(i) 表示以i为根的BST的个数 ,

那么G(n) = f(1)+ f(2)+ f(3)+ f(4)+ ........+ f(n)

即可得出 , 当i 为根节点时 , 左子树的节点个数为i-1个 , 右子树的节点个数为n-i个 , 那么我们可以得出

f(i) = G(i-1) * G(n-i)

代入第一个公式即可得出

  • G(n)= G(0)*G(n-1)+ G(1)*G(n-2)+ G(2)*G(n-3)+ .....+ G(n-1)*G(0)

卡特兰数_百度百科 (baidu.com)

那么不难看出上面的公式出现了许多的重复计算 , 因此我们可以通过一个memo[][] 数组来记录 memo[lo][hi] 的二叉树的个数 , 然后通过递归方法来计算左右子树的BST个数, 统计返回即可


递归方法 : cnt(lo, hi int) int

参数 :

  • lo : 节点范围的左边界
  • hi : 节点范围的右边界

返回值 : 指定范围存在的BST的个数


还需要注意的一点就是golang在定义二维数组的时候 , make([][]int,n+1) 只是定义了一个n+1 行的数组, 实际上每一行的capacity都是0 , 如下图所示

上面的代码的执行结果是 00000000000 , 因此实际上我们是需要再手动的去设置一下每个一维数组的容量

1
2
3
4
memo := make([][]int, n+1)
for i := range memo {
memo[i] = make([]int, n+1)
}

代码如下

注意由于在cnt 函数中递归调用了cnt函数 , 因此需要预先声明函数 var cnt func(lo, hi int) int

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
func numTrees(n int) int {
memo := make([][]int, n+1)
for i := range memo {
memo[i] = make([]int, n+1)
}
var cnt func(lo, hi int) int
cnt = func(lo, hi int) int {
if lo > hi {
return 1
}
res := 0
// 减少重复计算
if memo[lo][hi]!=0 {
return memo[lo][hi]
}
// 统计范围内的BST个数, 因此需要累加
for mid := lo; mid <= hi; mid++ {
left := cnt(lo, mid-1)
right := cnt(mid+1, hi)
// G(i-1) * G(n-i)
res += left * right
}
memo[lo][hi] = res
return res
}
return cnt(1, n)
}

语法

func len(V Type) int

其作用是用于计算数组(包括数组指针)、切片(slice )、map、channel、字符串等数据类型的长度,

注意,结构休(struct)、整型布尔等不能作为参数传给len函数。

  1. 数组或数组指针:返回元素个数
  2. map和slice: 元素个数
  3. channel : 通道中未读的元素个数
  4. 字符串:字节数,并非字符串的字符数
  5. 当V的值为nil值,len返回0

数组及切片

我们首先从概念上来区分数组以及切片 ,

  • 数组是具有相同 唯一类型 的一组已编号且长度固定

  • 切片(slice)是对数组一个连续片段的引用

    切片的长度可以在运行时修改,最小为 0 最大为相关数组的长度:切片是一个 长度可变的数组

    优点 因为切片是引用,所以它们不需要使用额外的内存并且比使用数组更有效率,所以在 Go 代码中 切片比数组更常用。

定义数组

var identifier [len]type

  • 可以在后面跟上{} 初始化元素
1
2
3
4
5
func main(){
var a [5]int
// 或者使用类型推断 , 如果是声明数组需要 有len or {elements...}
nums:=[]int{1,2,3,4,5,6}
}

定义切片

var identifier []type 不需要声明长度

1
2
3
func main(){
num:=[]int{}
}

一个切片在未初始化之前默认为 nil,长度为 0。

切片的初始化格式是:var slice1 []type = arr1[start:end]

注意区间格式是 [start,end)

1
2
nums := [5]int{}
fmt.Println(len(nums[0:3]))

上面代码的打印结果为3

通过数组赋值切片

1
2
3
4
5
func main(){
nums:=[]int{1,2,3,4,5,6}
slice:=&nums
slice:=nums[:]
}

那么通过这个机制 , 我们可以完成许多操作

比如 slice = slice[:len(slice)-1] 删除切片的最后一个元素

或者取得切片的左半边元素 slice = slice[0:(len(slice)+1)/2]

注意 绝对不要用指针指向 slice。切片本身已经是一个引用类型,所以它本身就是一个指针!!

方法定义

比如现在需要写一个简单的求两数之和的方法

简单的写法

1
2
3
func sum(a int ,b int) int{
return a+b
}

借助变量

1
2
3
sum:=func(a int ,b int) int{
return a+b
}

直接声明返回值

1
2
3
4
func sum(a int ,b int)(res int){
res = a+b
// return 这里就可以不写return了
}

FOR循环

Go 语言for循环遍历最全用法总结 - 知乎 (zhihu.com)

我们查看下面的代码

1
2
3
4
5
6
7
8
9
10
func main() {
nums := []int{1, 2, 3, 4, 5, 6}
for i := range nums {
fmt.Print(i, " ")
}
fmt.Print("\n")
for _, i := range nums {
fmt.Print(i, " ")
}
}

上面代码的打印结果为

1
2
0 1 2 3 4 5 
1 2 3 4 5 6

第一次循环中的 i 为索引 , 第二次循环中的 i 为nums数组中的元素

append()

  • append()用来将元素添加到切片末尾并返回结果。
  • 调用append函数必须用原来的切片变量接收返回值
  • append追加元素,如果slice还有容量的话,就会将新的元素放在原来slice后面的剩余空间里,当底层数组装不下的时候,Go就会创建新的底层数组来保存这个切片,slice地址也随之改变
  • 分配了新的地址后,再把原来slice中的元素逐个拷贝到新的slice中,并返回。

追加元素

1
2
3
4
5
6
7
8
9
func main(){
//append()为切片追加元素
s1 := []string {"火鸡面","辛拉面","汤达人"}
fmt.Printf("s1=%v len(s1)=%d cap(s1)=%d\n",s1,len(s1),cap(s1))

//调用append函数必须用原来的切片变量接收返回值
s1 = append(s1,"小当家") //append追加元素,原来的底层数组装不下的时候,Go就会创建新的底层数组来保存这个切片
fmt.Printf("s1=%v len(s1)=%d cap(s1)=%d\n",s1,len(s1),cap(s1))//cap增加两倍
}

range()

range 关键字用于遍历数组、切片、字符串、map 和通道等可迭代的数据结构。

使用 range 关键字,可以迭代一个集合并返回索引和元素值。在有些情况下,只需要元素值不需要索引,可以使用 _ 替换索引,表示不关心该值,比如:

1
2
3
4
5
goCopy Codenumbers := []int{1, 2, 3, 4, 5}

for _, number := range numbers {
fmt.Println(number)
}

输出结果为:

1
2
3
4
5
1
2
3
4
5

如果需要索引和元素值,使用以下语法:

1
2
3
goCopy Codefor index, value := range collection {
// Do something with index and value
}

其中 index 表示当前元素在集合中的索引,value 表示当前元素的值。

例如,遍历一个 map 并输出所有的 key 和 value:

1
2
3
4
5
6
7
8
9
ages := map[string]int{
"Alice": 25,
"Bob": 30,
"John": 20,
}

for name, age := range ages {
fmt.Printf("%s is %d years old\n", name, age)
}

输出结果为:

1
2
3
Alice is 25 years old
Bob is 30 years old
John is 20 years old