二十天刷leetcode【hot100】算法- day2[后端golang]

108 阅读6分钟

指针

6.三数之和

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请你返回所有和为 0 且不重复的三元组。

注意:答案中不可以包含重复的三元组。

a0c8f56e515ea7b452a1eae2cfaa322.png

leetcode 15. 三数之和

题解

该题需要先从小到大排序,后需要建立三个指针,从头到尾完成遍历,第一层遍历决定第一个元素(first),第二层遍历决定第二个元素(second = first + 1)跟第三个元素(third,初始化为最大的元素)。其中对于确认了first后,就要对secondthird进行首尾遍历。原则为:三者相加,大于target则左移third,小于则右移second。另外需要注意,不能输出相同的元素,又因为该数组一开始就经过排序,则可以跳过相等的两个元素。

package main

import (
	"fmt"
	"sort"
)

func threeSum(nums []int) [][]int {
	var res [][]int
	sort.Ints(nums) // 使用sort包中的Ints函数对切片进行排序

	for first := 0; first < len(nums); first++ {
		if first > 0 && nums[first] == nums[first-1] {
			continue // 跳过重复元素
		}

		target := -nums[first]
		third := len(nums) - 1

		for second := first + 1; second < len(nums)-1; second++ {
			if second > first+1 && nums[second] == nums[second-1] {
				continue // 跳过重复元素
			}

			for second < third && nums[second]+nums[third] > target {
				third-- // 向头部收缩
			}

			if second == third {
				break // 相等了,则直接跳出内层循环
			}

			if nums[second]+nums[third] == target {
				res = append(res, []int{nums[first], nums[second], nums[third]})
			}
		}
	}

	return res
}

func main() {
	arr := threeSum([]int{-1, 0, 1, 2, -1, -4})
	fmt.Println(arr) // 输出: [[-1 -1 2] [-1 0 1]]
}

7.最接近的两数和 - 字节-上海

给出一个数组和一个目标值,找出两个和最接近目标值的子项

题解

数组从大到小排序,双指针首尾收缩遍历,当前两者相加大于目标则收缩尾部,小于则收缩头部,用res记录最接近目标值的值

package main

import (
	"fmt"
	"math"
	"sort"
)

func testNear(arrNear []int, targetNear int) int {
	// 排序
	sort.Ints(arrNear)
	left, right := 0, len(arrNear)-1
	var res int

	for left < right {
		temp := arrNear[left] + arrNear[right]
		if temp == targetNear {
			return temp // 直接返回结果,因为找到了精确匹配
		} else if temp > targetNear {
			right--
		} else {
			left++
		}
		// 更新最接近的值
		if math.Abs(float64(targetNear-res)) > math.Abs(float64(targetNear-temp)) {
			res = temp
		}
	}

	return res
}

func main() {
	arrNear := []int{24, 69, 14, 37}
	targetNear := 60
	nearP := testNear(arrNear, targetNear)
	fmt.Printf("最接近的值是: %d\n", nearP) // 61
}

8 接雨水 - 腾讯cdg

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

3af1bc90ae8a2f9f4d214a5a15968f0.png leetcode 42. 接雨水

题解

一:动态规划

dp数组记录下标i及其左(leftMax )右(rightMax)边的所有柱子的最大高度。dp数组初始化,leftMax[0] = height[0];rightMax[len - 1] = height[len - 1];。dp数组遍历过程中,左右侧的值与当值的高度进行对比,更新dp数组

leftMax[i] = Math.max(leftMax[i - 1], height[i]);
rightMax[j] = Math.max(rightMax[j + 1], height[j]);

左右侧最高的两条柱子中,矮的那条减自身高度,即为当前柱子能接的水

// 动态规划
package main

import (
	"fmt"
)

func trapDp(height []int) int {
	if len(height) == 0 {
		return 0
	}
	len := len(height)

	// 下标i及其左边的所有柱子的最大高度
	leftMax := make([]int, len)
	leftMax[0] = height[0]

	// 下标i及其右边的所有柱子的最大高度
	rightMax := make([]int, len)
	rightMax[len-1] = height[len-1]

	// 计算每个位置左侧的最大高度
	for i := 1; i < len; i++ {
		leftMax[i] = max(leftMax[i-1], height[i])
	}

	// 计算每个位置右侧的最大高度
	for j := len - 2; j >= 0; j-- {
		rightMax[j] = max(rightMax[j+1], height[j])
	}

	var ans int

	// 计算总的水量
	for k := 0; k < len; k++ {
		// 左右侧最高的两条柱子中,矮的那条减自身高度,即为当前柱子能接的水
		ans += min(leftMax[k], rightMax[k]) - height[k]
	}

	return ans
}

// 辅助函数:返回两个整数中的较大值
func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}

// 辅助函数:返回两个整数中的较小值
func min(a, b int) int {
	if a < b {
		return a
	}
		return b
}

func main() {
	height := []int{0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1}
	result := trapDp(height)
	fmt.Println(result) // 输出: 6
}
二、双指针

头尾双指针收缩遍历,详细见代码解

// 双指针
package main

import (
	"fmt"
)

func trap(height []int) int {
	if len(height) == 0 {
		return 0
	}

	left, right := 0, len(height)-1
	leftMax, rightMax := height[left], height[right]
	ans := 0

	for left < right {
		// 更新左右两侧的最大值
		if height[left] > leftMax {
			leftMax = height[left]
		}
		if height[right] > rightMax {
			rightMax = height[right]
		}

		// 移动较矮的指针并累加可以积累的雨水
		if height[left] < height[right] {
			ans += leftMax - height[left]
			left++
		} else {
			ans += rightMax - height[right]
			right--
		}
	}

	return ans
}

func main() {
	height := []int{0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1}
	result := trap(height)
	fmt.Println(result) // 输出: 6
}

9 无重复字符串的最长子串

给定一个字符串s ,请你找出其中不含有重复字符的 最长 子串的长度。

3696ddbc487bba37d8516621a4debf1.png leetcode 3.无重复字符串的最长子串

题解

双指针搭配set, 用set去重,左指针移动, set移除元素,右指针移动,且右指针元素不存在于set中,则加入set,最后根据左右指针位置更新最大长度

package main

import (
	"fmt"
)

func lengthOfLongestSubstring(s string) int {
	// 使用map作为set,用于存储当前考虑的子字符串中的字符
	charSet := make(map[rune]bool)
	left, right := 0, -1
	ans := 0

	for left < len(s) {
		if left > 0 {
			// 移除左指针指向的字符
			delete(charSet, rune(s[left-1]))
		}

		// 尝试移动右指针
		for right+1 < len(s) && !charSet[rune(s[right+1])] {
			// 右指针指向的字符不在集合中,则加入集合并移动右指针
			charSet[rune(s[right+1])] = true
			right++
		}

		// 更新最长子字符串的长度
		ans = max(ans, right-left+1)

		// 移动左指针
		left++
	}

	return ans
}

// 辅助函数:返回两个整数中的较大值
func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}

func main() {
	s := "abcabcbb"
	result := lengthOfLongestSubstring(s)
	fmt.Println(result) // 输出: 3
}

10 找到字符串中所有字母异位词

给定两个字符串 sp,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。

异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。

a484cc3bc15eb0ca3263d5fe3d554af.png leetcode 438.找到字符串中所有字母异位词

题解

使用《位置数组》记录当前值在英文字母中的顺序。初始化遍历先把p字符串和s下标0pLen - 1的子串遍历完。如这个时候如果位置数组相等,则把下标0推进数组。后将s剩下的数据遍历完成。

package main

import (
	"fmt"
)

func findAnagrams(s, p string) []int {
	sLen, pLen := len(s), len(p)
	if sLen < pLen {
		return []int{}
	}

	ans := []int{}
	sCount := make([]int, 26)
	pCount := make([]int, 26)

	// 初始化pCount和sCount(s的前pLen个字符)
	for i := 0; i < pLen; i++ {
		sCount[s[i]-'a']++
		pCount[p[i]-'a']++
	}

	// 检查初始窗口是否匹配
	if arraysEqual(sCount, pCount) {
		ans = append(ans, 0)
	}

	// 滑动窗口
	for i := 0; i < sLen-pLen; i++ {
		// 移除窗口左侧的字符
		sCount[s[i]-'a']--
		// 添加窗口右侧的字符
		sCount[s[i+pLen]-'a']++

		// 检查窗口是否匹配
		if arraysEqual(sCount, pCount) {
			ans = append(ans, i+1)
		}
	}

	return ans
}

// 辅助函数:检查两个整数数组是否相等
func arraysEqual(a, b []int) bool {
	if len(a) != len(b) {
		return false
	}
	for i := range a {
		if a[i] != b[i] {
			return false
		}
	}
	return true
}

func main() {
	s := "cbaebabacd"
	p := "abc"
	arr := findAnagrams(s, p)
	fmt.Println(arr) // 输出: [0 6]
}

关注我的公众号,回复 100905A2 获取hot100算法在线链接

公众号.jpg