0001-0100-Easy

1.两数之和(3)

  • 题目

给定一个整数数组 nums 和一个目标值 target,
请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。
示例:给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]
  • 解答思路

No. 思路 时间复杂度 空间复杂度
01 暴力法: 2层循环遍历 O(n^2) O(1)
02 两遍哈希遍历 O(n) O(n)
03(最优) 一遍哈希遍历 O(n) O(n)
# 暴力法: 2层循环遍历
func twoSum(nums []int, target int) []int {
	for i := 0; i < len(nums); i++ {
		for j := i + 1; j < len(nums); j++ {
			if nums[i]+nums[j] == target {
				return []int{i, j}
			}
		}
	}
	return []int{}
}

# 两遍哈希遍历
func twoSum(nums []int, target int) []int {
	m := make(map[int]int,len(nums))
	for k, v := range nums{
		m[v] = k
	}

	for i := 0; i < len(nums); i++{
		b := target - nums[i]
		if num, ok := m[b]; ok && num != i{
			return []int{i,m[b]}
		}
	}
	return []int{}
}

# 一遍哈希遍历
func twoSum(nums []int, target int) []int {
	m := make(map[int]int, len(nums))
	for i, b := range nums {
		if j, ok := m[target-b]; ok {
			return []int{j, i}
		}
		m[b] = i
	}
	return nil
}

7.整数反转(2)

  • 题目

给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。
示例 1:输入: 123 输出: 321
示例 2:输入: -123 输出: -321
示例 3:输入: 120 输出: 21
注意:假设我们的环境只能存储得下 32 位的有符号整数,则其数值范围为 [−2^31,  2^31 − 1]。
请根据这个假设,如果反转后整数溢出那么就返回 0。
  • 解答思路

No. 思路 时间复杂度 空间复杂度
01 使用符号标记,转成正数,循环得到%10的余数,再加上符号 O(log(x)) O(1)
02(最优) 对x进行逐个%10取个位,一旦溢出,直接跳出循环 O(log(x)) O(1)
// 使用符号标记,转成正数,循环得到%10的余数,再加上符号
func reverse(x int) int {
	flag := 1
	if x < 0 {
		flag = -1
		x = -1 * x
	}

	result := 0
	for x > 0 {
		temp := x % 10
		x = x / 10

		result = result*10 + temp
	}

	result = flag * result
	if result > math.MaxInt32 || result < math.MinInt32 {
		result = 0
	}
	return result
}

// 对x进行逐个%10取个位,一旦溢出,直接跳出循环
func reverse(x int) int {
	result := 0
	for x != 0 {
		temp := x % 10
		result = result*10 + temp
		if result > math.MaxInt32 || result < math.MinInt32 {
			return 0
		}
		x = x / 10
	}
	return result
}

9.回文数(3)

  • 题目

判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。
示例 1:	输入: 121	输出: true
示例 2:输入: -121	输出: false
解释: 从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。
示例 3:输入: 10  	输出: false
解释: 从右向左读, 为 01 。因此它不是一个回文数。
进阶: 你能不将整数转为字符串来解决这个问题吗?
  • 解答思路

No. 思路 时间复杂度 空间复杂度
01(最优) 数学解法,取出后半段数字进行翻转,然后判断是否相等 O(log(x)) O(1)
02 转成字符串,依次判断 O(log(x)) O(log(x))
03 转成byte数组,依次判断,同2 O(log(x)) O(log(x))
// 数学解法,取出后半段数字进行翻转,然后判断是否相等
func isPalindrome(x int) bool {
	if x < 0 || (x%10 == 0 && x != 0) {
		return false
	}

	revertedNumber := 0
	for x > revertedNumber {
		temp := x % 10
		revertedNumber = revertedNumber*10 + temp
		x = x / 10
	}
	// for example:
	// x = 1221  => x = 12 revertedNumber = 12
	// x = 12321 => x = 12 revertedNumber = 123
	return x == revertedNumber || x == revertedNumber/10
}

// 转成字符串,依次判断
func isPalindrome(x int) bool {
	if x < 0 {
		return false
	}

	s := strconv.Itoa(x)
	for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
		if s[i] != s[j] {
			return false
		}
	}
	return true
}

// 转成byte数组,依次判断,同2
func isPalindrome(x int) bool {
	if x < 0 {
		return false
	}
	arrs := []byte(strconv.Itoa(x))
	Len := len(arrs)
	for i := 0; i < Len/2; i++ {
		if arrs[i] != arrs[Len-i-1] {
			return false
		}
	}
	return true
}

13.罗马数字转整数(2)

  • 题目

罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。
字符          数值
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。
给定一个罗马数字,将其转换成整数。输入确保在 1 到 3999 的范围内。
示例 1:输入: "III" 输出: 3
示例 2:	输入: "IV" 输出: 4
示例 3:	输入: "IX"	输出: 9
示例 4:	输入: "LVIII"	输出: 58 解释: L = 50, V= 5, III = 3.
示例 5: 输入: "MCMXCIV"	输出: 1994 解释: M = 1000, CM = 900, XC = 90, IV = 4.
  • 解答思路

No. 思路 时间复杂度 空间复杂度
01 本质上其实就是全部累加,然后遇到特殊的就做判断。使用一个字段记录递增 O(n) O(1)
02(最优) 从右到左遍历字符串,如果当前字符代表的值不小于其右边,就加上该值;否则就减去该值。 O(n) O(1)
// 带标记位
func romanToInt(s string) int {
	m := map[byte]int{
		'I': 1,
		'V': 5,
		'X': 10,
		'L': 50,
		'C': 100,
		'D': 500,
		'M': 1000,
	}
	result := 0
	last := 0

	for i := len(s) - 1; i >= 0; i-- {
		current := m[s[i]]
		flag := 1
		if current < last {
			flag = -1
		}
		result = result + flag*current
		last = current
	}
	return result
}

// 不带标记位,小于则减去2倍数
func romanToInt(s string) int {
	m := map[byte]int{
		'I': 1,
		'V': 5,
		'X': 10,
		'L': 50,
		'C': 100,
		'D': 500,
		'M': 1000,
	}
	result := 0
	last := 0

	for i := len(s) - 1; i >= 0; i-- {
		current := m[s[i]]
		if current < last {
			result = result - current
		}else {
			result = result + current
		}
		last = current
	}
	return result
}

14.最长公共前缀(6)

  • 题目

编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 ""。
示例 1:输入: ["flower","flow","flight"] 输出: "fl"
示例 2:输入: ["dog","racecar","car"] 输出: ""
解释: 输入不存在公共前缀。
说明: 所有输入只包含小写字母 a-z 。
  • 解答思路

No. 思路 时间复杂度 空间复杂度
01 先找最短的一个字符串,依次比较最短字符串子串是否是其他字符串子串 O(n^2)/O(n*m) O(1)
02 纵向扫描(暴力法):直接取第一个字符串作为最长公共前缀,将其每个字符遍历过一次 O(n^2)/O(n*m) O(1)
03(最优) 排序后,然后计算第一个,和最后一个字符串的最长前缀 O(nlog(n)) O(1)
04 trie树 O(n^2) O(n^2)
05 水平扫描法:比较前2个字符串得到最长前缀,然后跟第3个比较得到一个新的最长前缀,继续比较,直到最后 O(n^2)/O(n*m) O(1)
06 分治法 O(n^2) O(1)
// 先找最短的一个字符串,依次比较最短字符串子串是否是其他字符串子串
func longestCommonPrefix(strs []string) string {
	if len(strs) == 0{
		return ""
	}
	if len(strs) == 1{
		return strs[0]
	}

	short := strs[0]
	for _, s := range strs{
		if len(short) > len(s){
			short = s
		}
	}

	for i := range short{
		shortest := short[:i+1]
		for _,str := range strs{
			if strings.Index(str,shortest) != 0{
				return short[:i]
			}
		}
	}
	return short
}

// 暴力法:直接依次遍历
func longestCommonPrefix(strs []string) string {
	if len(strs) == 0 {
		return ""
	}
	if len(strs) == 1 {
		return strs[0]
	}

	length := 0

	for i := 0; i < len(strs[0]); i++ {
		char := strs[0][i]
		for j := 1; j < len(strs); j++ {
			if i >= len(strs[j]) || char != strs[j][i] {
				return strs[0][:length]
			}
		}
		length++
	}
	return strs[0][:length]
}

// 排序后,遍历比较第一个,和最后一个字符串
func longestCommonPrefix(strs []string) string {
	if len(strs) == 0{
		return ""
	}
	if len(strs) == 1{
		return strs[0]
	}

	sort.Strings(strs)
	first := strs[0]
	last := strs[len(strs)-1]
	i := 0
	length := len(first)
	if len(last) < length{
		length = len(last)
	}
	for i < length{
		if first[i] != last[i]{
			return first[:i]
		}
		i++
	}

	return first[:i]
}

// trie树
var trie [][]int
var index int

func longestCommonPrefix(strs []string) string {
	if len(strs) == 0 {
		return ""
	}
	if len(strs) == 1 {
		return strs[0]
	}

	trie = make([][]int, 2000)
	for k := range trie {
		value := make([]int, 26)
		trie[k] = value
	}
	insert(strs[0])

	minValue := math.MaxInt32
	for i := 1; i < len(strs); i++ {
		retValue := insert(strs[i])
		if minValue > retValue {
			minValue = retValue
		}
	}
	return strs[0][:minValue]
}

func insert(str string) int {
	p := 0
	count := 0
	for i := 0; i < len(str); i++ {
		ch := str[i] - 'a'
		// fmt.Println(string(str[i]),p,ch,trie[p][ch])
		if value := trie[p][ch]; value == 0 {
			index++
			trie[p][ch] = index
		} else {
			count++
		}
		p = trie[p][ch]
	}
	return count
}

// 水平扫描法:比较前2个字符串得到最长前缀,然后跟第3个比较得到一个新的最长前缀,继续比较,直到最后
func longestCommonPrefix(strs []string) string {
	if len(strs) == 0 {
		return ""
	}
	if len(strs) == 1 {
		return strs[0]
	}

	commonStr := common(strs[0], strs[1])
	if commonStr == "" {
		return ""
	}
	for i := 2; i < len(strs); i++ {
		if commonStr == "" {
			return ""
		}
		commonStr = common(commonStr, strs[i])
	}
	return commonStr
}

func common(str1, str2 string) string {
	length := 0
	for i := 0; i < len(str1); i++ {
		char := str1[i]
		if i >= len(str2) || char != str2[i] {
			return str1[:length]
		}
		length++
	}
	return str1[:length]
}

// 分治法
func longestCommonPrefix(strs []string) string {
	if len(strs) == 0 {
		return ""
	}
	if len(strs) == 1 {
		return strs[0]
	}

	return commonPrefix(strs, 0, len(strs)-1)
}

func commonPrefix(strs []string, left, right int) string {
	if left == right {
		return strs[left]
	}

	middle := (left + right) / 2
	leftStr := commonPrefix(strs, left, middle)
	rightStr := commonPrefix(strs, middle+1, right)
	return commonPrefixWord(leftStr, rightStr)
}

func commonPrefixWord(leftStr, rightStr string) string {
	if len(leftStr) > len(rightStr) {
		leftStr = leftStr[:len(rightStr)]
	}

	if len(leftStr) < 1 {
		return leftStr
	}

	for i := 0; i < len(leftStr); i++ {
		if leftStr[i] != rightStr[i] {
			return leftStr[:i]
		}
	}
	return leftStr
}

20.有效的括号(3)

  • 题目

给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。
有效字符串需满足:
    左括号必须用相同类型的右括号闭合。
    左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。
示例 1: 输入: "()" 输出: true
示例 2: 输入: "()[]{}" 输出: true
示例 3: 输入: "(]" 输出: false
示例 4: 输入: "([)]" 输出: false
示例 5: 输入: "{[]}" 输出: true
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 使用栈结构实现栈 O(n) O(n)
02 借助数组实现栈 O(n) O(n)
03 借助数组实现栈,使用数字表示来匹配 O(n) O(n)
// 使用栈结构实现
func isValid(s string) bool {
	st := new(stack)
	for _, char := range s {
		switch char {
		case '(', '[', '{':
			st.push(char)
		case ')', ']', '}':
			ret, ok := st.pop()
			if !ok || ret != match[char] {
				return false
			}
		}
	}

	if len(*st) > 0 {
		return false
	}
	return true
}

var match = map[rune]rune{
	')': '(',
	']': '[',
	'}': '{',
}

type stack []rune

func (s *stack) push(b rune) {
	*s = append(*s, b)
}
func (s *stack) pop() (rune, bool) {
	if len(*s) > 0 {
		res := (*s)[len(*s)-1]
		*s = (*s)[:len(*s)-1]
		return res, true
	}
	return 0, false
}

// 借助数组实现栈
func isValid(s string) bool {
	if s == "" {
		return true
	}

	stack := make([]rune, len(s))
	length := 0
	var match = map[rune]rune{
		')': '(',
		']': '[',
		'}': '{',
	}

	for _, char := range s {
		switch char {
		case '(', '[', '{':
			stack[length] = char
			length++
		case ')', ']', '}':
			if length == 0 {
				return false
			}
			if stack[length-1] != match[char]{
				return false
			} else {
				length--
			}
		}
	}
	return length == 0
}

// 借助数组实现栈,使用数字表示来匹配
func isValid(s string) bool {
	if s == "" {
		return true
	}

	stack := make([]int, len(s))
	length := 0
	var match = map[rune]int{
		')': 1,
		'(': -1,
		']': 2,
		'[': -2,
		'}': 3,
		'{': -3,
	}

	for _, char := range s {
		switch char {
		case '(', '[', '{':
			stack[length] = match[char]
			length++
		case ')', ']', '}':
			if length == 0 {
				return false
			}
			if stack[length-1]+match[char] != 0 {
				return false
			} else {
				length--
			}
		}
	}
	return length == 0
}

21.合并两个有序链表(3)

  • 题目

将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 
示例:输入:1->2->4, 1->3->4 输出:1->1->2->3->4->4
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01(最优) 迭代遍历 O(n) O(1)
02 递归实现 O(n) O(n)
03 迭代 O(n) O(1)
// 迭代遍历
func mergeTwoLists(l1 *ListNode, l2 *ListNode) *ListNode {
	if l1 == nil {
		return l2
	}
	if l2 == nil {
		return l1
	}

	var head, node *ListNode
	if l1.Val < l2.Val {
		head = l1
		node = l1
		l1 = l1.Next
	} else {
		head = l2
		node = l2
		l2 = l2.Next
	}

	for l1 != nil && l2 != nil {
		if l1.Val < l2.Val {
			node.Next = l1
			l1 = l1.Next
		} else {
			node.Next = l2
			l2 = l2.Next
		}
		node = node.Next
	}
	if l1 != nil {
		node.Next = l1
	}
	if l2 != nil {
		node.Next = l2
	}
	return head
}

// 递归遍历
func mergeTwoLists(l1 *ListNode, l2 *ListNode) *ListNode {
	if l1 == nil {
		return l2
	}
	if l2 == nil {
		return l1
	}

	if l1.Val < l2.Val{
		l1.Next = mergeTwoLists(l1.Next,l2)
		return l1
	}else {
		l2.Next = mergeTwoLists(l1,l2.Next)
		return l2
	}
}

#
func mergeTwoLists(l1 *ListNode, l2 *ListNode) *ListNode {
	res := &ListNode{}
	temp := res
	for l1 != nil && l2 != nil {
		if l1.Val < l2.Val {
			temp.Next = l1
			l1 = l1.Next
		} else {
			temp.Next = l2
			l2 = l2.Next
		}
		temp = temp.Next
	}
	if l1 != nil {
		temp.Next = l1
	} else {
		temp.Next = l2
	}
	return res.Next
}

26.删除排序数组中的重复项(2)

  • 题目

给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。
示例 1: 给定数组 nums = [1,1,2], 
函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。 
你不需要考虑数组中超出新长度后面的元素。
示例 2: 给定 nums = [0,0,1,1,1,2,2,3,3,4],
函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。
你不需要考虑数组中超出新长度后面的元素。
说明: 为什么返回数值是整数,但输出的答案是数组呢?
请注意,输入数组是以“引用”方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。
你可以想象内部操作如下:
// nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝
int len = removeDuplicates(nums);
// 在函数里修改输入数组对于调用者是可见的。
// 根据你的函数返回的长度, 它会打印出数组中该长度范围内的所有元素。
for (int i = 0; i < len; i++) {
    print(nums[i]);
}
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 双指针法 O(n) O(1)
02(最优) 计数法 O(n) O(1)
// 双指针法
func removeDuplicates(nums []int) int {
	i , j , length := 0, 1, len(nums)
	for ; j < length; j++{
		if nums[i] == nums[j]{
			continue
		}
		i++
		nums[i] = nums[j]
	}
	return i+1
}

// 计数法
func removeDuplicates(nums []int) int {
	count := 1
	for i := 0; i < len(nums)-1; i++ {
		if nums[i] != nums[i+1] {
			nums[count] = nums[i+1]
			count++
		}
	}
	return count
}

27.移除元素(3)

  • 题目

给定一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
示例 1: 给定 nums = [3,2,2,3], val = 3,
函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。
你不需要考虑数组中超出新长度后面的元素。
示例 2: 给定 nums = [0,1,2,2,3,0,4,2], val = 2,
函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。
注意这五个元素可为任意顺序。
你不需要考虑数组中超出新长度后面的元素。
说明: 为什么返回数值是整数,但输出的答案是数组呢?
请注意,输入数组是以“引用”方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。
你可以想象内部操作如下:
// nums 是以“引用”方式传递的。也就是说,不对实参作任何拷贝
int len = removeElement(nums, val);
// 在函数里修改输入数组对于调用者是可见的。
// 根据你的函数返回的长度, 它会打印出数组中该长度范围内的所有元素。
for (int i = 0; i < len; i++) {
    print(nums[i]);
}
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01(最优) 双指针,数字前移 O(n) O(1)
02 双指针,出现重复最后数字前移 O(n) O(1)
03 首位指针法 O(n) O(1)
// 双指针,数字前移
func removeElement(nums []int, val int) int {
	i := 0
	for j := 0; j < len(nums); j++{
		if nums[j] != val{
			nums[i] = nums[j]
			i++
		}
	}
	return i
}

// 双指针,出现重复最后数字前移
func removeElement(nums []int, val int) int {
	i := 0
	n := len(nums)
	for i < n{
		if nums[i] == val{
			nums[i] = nums[n-1]
			n--
		}else {
			i++
		}
	}
	return n
}

// 首位指针法
func removeElement(nums []int, val int) int {
	i, j := 0, len(nums)-1
	for {
		// 从左向右找到等于 val 的位置
		for i < len(nums) && nums[i] != val {
			i++
		}
		// 从右向左找到不等于 val 的位置
		for j >= 0 && nums[j] == val {
			j--
		}
		if i >= j {
			break
		}
		// fmt.Println(i,j)
		nums[i], nums[j] = nums[j], nums[i]
	}
	return i
}

28.实现strStr()(4)

  • 题目

实现 strStr() 函数。
给定一个 haystack 字符串和一个 needle 字符串,
在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。
如果不存在,则返回-1。
示例 1:输入: haystack = "hello", needle = "ll" 输出: 2
示例 2: 输入: haystack = "aaaaa", needle = "bba" 输出: -1
说明: 当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。
对于本题而言,当 needle 是空字符串时我们应当返回 0 。
这与C语言的 strstr() 以及 Java的 indexOf() 定义相符。
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01(最优) Sunday算法 O(n) O(1)
02 直接匹配 O(n) O(1)
03 系统函数 O(n) O(1)
04 kmp算法 O(n) O(n)
// Sunday算法
func strStr(haystack string, needle string) int {
	if needle == ""{
		return 0
	}
	if len(needle) > len(haystack){
		return -1
	}
	// 计算模式串needle的偏移量
	m := make(map[int32]int)
	for k,v := range needle{
		m[v] = len(needle)-k
	}

	index := 0
	for index+len(needle) <= len(haystack){
		// 匹配字符串
		str := haystack[index:index+len(needle)]
		if str == needle{
			return index
		}else {
			if index + len(needle) >= len(haystack){
				return -1
			}
			// 后一位字符串
			next := haystack[index+len(needle)]
			if nextStep,ok := m[int32(next)];ok{
				index = index+nextStep
			}else {
				index = index+len(needle)+1
			}
		}
	}
	if index + len(needle) >= len(haystack){
		return -1
	}else {
		return index
	}
}

// 
func strStr(haystack string, needle string) int {
	hlen, nlen := len(haystack), len(needle)
	for i := 0; i <= hlen-nlen; i++ {
		if haystack[i:i+nlen] == needle {
			return i
		}
	}
	return -1
}

//
func strStr(haystack string, needle string) int {
	return strings.Index(haystack, needle)
}

//
func strStr(haystack string, needle string) int {
	if len(needle) == 0 {
		return 0
	}

	next := getNext(needle)

	i := 0
	j := 0
	for i < len(haystack) && j < len(needle) {
		if j == -1 || haystack[i] == needle[j] {
			i++
			j++
		} else {
			j = next[j]
		}
	}

	if j == len(needle) {
		return i - j
	}
	return -1
}

// 求next数组
func getNext(str string) []int {
	var next = make([]int, len(str))
	next[0] = -1

	i := 0
	j := -1

	for i < len(str)-1 {
		if j == -1 || str[i] == str[j] {
			i++
			j++
			next[i] = j
		} else {
			j = next[j]
		}
	}
	return next
}

35.搜索插入位置(3)

  • 题目

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。
如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
你可以假设数组中无重复元素。
示例 1: 输入: [1,3,5,6], 5 输出: 2
示例 2: 输入: [1,3,5,6], 2 输出: 1
示例 3: 输入: [1,3,5,6], 7 输出: 4
示例 4: 输入: [1,3,5,6], 0 输出: 0
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01(最优) 二分查找 O(log(n)) O(1)
02 顺序查找 O(n) O(1)
03 顺序查找 O(n) O(1)
// 二分查找
func searchInsert(nums []int, target int) int {
	low, high := 0, len(nums)-1
	for low <= high {
		mid := (low + high) / 2
		switch {
		case nums[mid] < target:
			low = mid + 1
		case nums[mid] > target:
			high = mid - 1
		default:
			return mid
		}
	}
	return low
}

// 顺序查找
func searchInsert(nums []int, target int) int {
	i := 0
	for i < len(nums) && nums[i] < target {
		if nums[i] == target {
			return i
		}
		i++
	}
	return i
}

// 顺序查找
func searchInsert(nums []int, target int) int {
	for i := 0; i < len(nums); i++ {
		if nums[i] >= target {
			return i
		}
	}
	return len(nums)
}

38.报数(2)

  • 题目

报数序列是一个整数序列,按照其中的整数的顺序进行报数,得到下一个数。其前五项如下:
1.     1
2.     11
3.     21
4.     1211
5.     111221
1 被读作  "one 1"  ("一个一") , 即 11。
11 被读作 "two 1s" ("两个一"), 即 21。
21 被读作 "one 2",  "one 1" ("一个二" ,  "一个一") , 即 1211。
给定一个正整数 n(1 ≤ n ≤ 30),输出报数序列的第 n 项。
注意:整数顺序将表示为一个字符串。
示例 1:输入: 1 输出: "1"
示例 2: 输入: 4 输出: "1211"
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 (最优) 递推+双指针计数 O(n^2) O(1)
02 递归+双指针计数 O(n^2) O(n)
// 递推+双指针计数
func countAndSay(n int) string {
	strs := []byte{'1'}
	for i := 1; i < n; i++ {
		strs = say(strs)
	}
	return string(strs)
}

func say(strs []byte) []byte {
	result := make([]byte, 0, len(strs)*2)

	i, j := 0, 1
	for i < len(strs) {
		for j < len(strs) && strs[i] == strs[j] {
			j++
		}
		// 几个几
		result = append(result, byte(j-i+'0'))
		result = append(result, strs[i])
		i = j
	}
	return result
}

// 递归+双指针计数
func countAndSay(n int) string {
	if n == 1 {
		return "1"
	}
	strs := countAndSay(n - 1)

	result := make([]byte, 0, len(strs)*2)

	i, j := 0, 1
	for i < len(strs) {
		for j < len(strs) && strs[i] == strs[j] {
			j++
		}
		// 几个几
		result = append(result, byte(j-i+'0'))
		result = append(result, strs[i])
		i = j
	}
	return string(result)
}

53.最大子序和(5)

  • 题目

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例: 输入: [-2,1,-3,4,-1,2,1,-5,4], 输出: 6 解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
进阶: 如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01(最优) 贪心法 O(n) O(1)
02 暴力法 O(n^2) O(1)
03 动态规划 O(n) O(n)
04 动态规划 O(n) O(1)
05 分治 O(nlog(n)) O(log(n))
// 贪心法
func maxSubArray(nums []int) int {
	result := nums[0]
	sum := 0
	for i := 0; i < len(nums); i++ {
		if sum > 0 {
			sum += nums[i]
		} else {
			sum = nums[i]
		}
		if sum > result {
			result = sum
		}
	}
	return result
}

// 暴力法
func maxSubArray(nums []int) int {
	result := math.MinInt32

	for i := 0; i < len(nums); i++ {
		sum := 0
		for j := i; j < len(nums); j++ {
			sum += nums[j]
			if sum > result {
				result = sum
			}
		}
	}
	return result
}

// 
func maxSubArray(nums []int) int {
	dp := make([]int, len(nums))
	dp[0] = nums[0]
	result := nums[0]

	for i := 1; i < len(nums); i++ {
		if dp[i-1]+nums[i] > nums[i] {
			dp[i] = dp[i-1] + nums[i]
		} else {
			dp[i] = nums[i]
		}

		if dp[i] > result {
			result = dp[i]
		}
	}
	return result
}

// 动态规划
func maxSubArray(nums []int) int {
	dp := nums[0]
	result := dp

	for i := 1; i < len(nums); i++ {
		if dp+nums[i] > nums[i] {
			dp = dp + nums[i]
		} else {
			dp = nums[i]
		}

		if dp > result {
			result = dp
		}
	}
	return result
}

// 分治法
func maxSubArray(nums []int) int {
	result := maxSubArr(nums, 0, len(nums)-1)
	return result
}

func maxSubArr(nums []int, left, right int) int {
	if left == right {
		return nums[left]
	}

	mid := (left + right) / 2
	leftSum := maxSubArr(nums, left, mid)        // 最大子序在左边
	rightSum := maxSubArr(nums, mid+1, right)    // 最大子序在右边
	midSum := findMaxArr(nums, left, mid, right) // 跨中心
	result := max(leftSum, rightSum)
	result = max(result, midSum)
	return result
}

func findMaxArr(nums []int, left, mid, right int) int {
	leftSum := math.MinInt32
	sum := 0
	// 从右到左
	for i := mid; i >= left; i-- {
		sum += nums[i]
		leftSum = max(leftSum, sum)
	}

	rightSum := math.MinInt32
	sum = 0
	// 从左到右
	for i := mid + 1; i <= right; i++ {
		sum += nums[i]
		rightSum = max(rightSum, sum)
	}
	return leftSum + rightSum
}

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

58.最后一个单词的长度(2)

  • 题目

给定一个仅包含大小写字母和空格 ' ' 的字符串,返回其最后一个单词的长度。
如果不存在最后一个单词,请返回 0 。
说明:一个单词是指由字母组成,但不包含任何空格的字符串。
示例: 输入: "Hello World" 输出: 5
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01(最优) 调用系统函数,切割为数组取最后一个值 O(n) O(1)
02 遍历统计 O(n) O(1)
// 调用系统函数,切割为数组取最后一个值
func lengthOfLastWord(s string) int {
	arr := strings.Split(strings.Trim(s, " "), " ")
	return len(arr[len(arr)-1])
}

// 遍历统计
func lengthOfLastWord(s string) int {
	length := len(s)
	if length == 0 {
		return 0
	}

	result := 0
	for i := length - 1; i >= 0; i-- {
		if s[i] == ' ' {
			if result > 0 {
				return result
			}
			continue
		}
		result++
	}
	return result
}

66.加一(2)

  • 题目

给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一。
最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。
你可以假设除了整数 0 之外,这个整数不会以零开头。
示例 1: 输入: [1,2,3] 输出: [1,2,4] 解释: 输入数组表示数字 123。
示例 2: 输入: [4,3,2,1] 输出: [4,3,2,2] 解释: 输入数组表示数字 4321。
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 直接模拟 O(n) O(1)
02(最优) 直接模拟 O(n) O(1)
// 模拟进位
func plusOne(digits []int) []int {
	length := len(digits)
	if length == 0 {
		return []int{1}
	}

	digits[length-1]++
	for i := length - 1; i > 0; i-- {
		if digits[i] < 10 {
			break
		}
		digits[i] = digits[i] - 10
		digits[i-1]++
	}

	if digits[0] > 9 {
		digits[0] = digits[0] - 10
		digits = append([]int{1}, digits...)
	}

	return digits
}

// 模拟进位
func plusOne(digits []int) []int {
	for i := len(digits) - 1; i >= 0; i-- {
		if digits[i] < 9 {
			digits[i]++
			return digits
		} else {
			digits[i] = 0
		}
	}
	return append([]int{1}, digits...)
}

67.二进制求和(2)

  • 题目

给定两个二进制字符串,返回他们的和(用二进制表示)。
输入为非空字符串且只包含数字 1 和 0。
示例 1: 输入: a = "11", b = "1" 输出: "100"
示例 2:输入: a = "1010", b = "1011" 输出: "10101"
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 数组 O(n) O(n)
02(最优) 模拟 O(n) O(n)
// 转换成数组模拟
func addBinary(a string, b string) string {
	if len(a) < len(b) {
		a, b = b, a
	}
	length := len(a)

	A := transToInt(a, length)
	B := transToInt(b, length)

	return makeString(add(A, B))
}

func transToInt(s string, length int) []int {
	result := make([]int, length)
	ls := len(s)
	for i, b := range s {
		result[length-ls+i] = int(b - '0')
	}
	return result
}

func add(a, b []int) []int {
	length := len(a) + 1
	result := make([]int, length)
	for i := length - 1; i >= 1; i-- {
		temp := result[i] + a[i-1] + b[i-1]
		result[i] = temp % 2
		result[i-1] = temp / 2
	}
	i := 0
	for i < length-1 && result[i] == 0 {
		i++
	}
	return result[i:]
}

func makeString(nums []int) string {
	bytes := make([]byte, len(nums))
	for i := range bytes {
		bytes[i] = byte(nums[i]) + '0'
	}
	return string(bytes)
}

// 直接模拟
func addBinary(a string, b string) string {
	i := len(a) - 1
	j := len(b) - 1
	result := ""
	flag := 0
	current := 0

	for i >= 0 || j >= 0 {
		intA, intB := 0, 0
		if i >= 0 {
			intA = int(a[i] - '0')
		}
		if j >= 0 {
			intB = int(b[j] - '0')
		}
		current = intA + intB + flag
		flag = 0
		if current >= 2 {
			flag = 1
			current = current - 2
		}
		cur := strconv.Itoa(current)
		result = cur + result
		i--
		j--
	}
	if flag == 1 {
		result = "1" + result
	}
	return result
}

69.x的平方根 (5)

  • 题目

实现 int sqrt(int x) 函数。
计算并返回 x 的平方根,其中 x 是非负整数。
由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。
示例 1:输入: 4 输出: 2
示例 2:输入: 8 输出: 2
说明: 8 的平方根是 2.82842..., 
     由于返回类型是整数,小数部分将被舍去。
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 系统函数 O(log(n)) O(1)
02 系统函数 O(log(n)) O(1)
03(最优) 牛顿迭代法 O(log(n)) O(1)
04 二分查找法 O(log(n)) O(1)
05 暴力法:遍历 O(n) O(1)
// 系统函数
func mySqrt(x int) int {
	result := int(math.Sqrt(float64(x)))
	return result
}

// 系统函数
func mySqrt(x int) int {
	result := math.Floor(math.Sqrt(float64(x)))
	return int(result)
}

// 牛顿迭代法
func mySqrt(x int) int {
	result := x
	for result*result > x {
		result = (result + x/result) / 2
	}
	return result
}

// 二分查找法
func mySqrt(x int) int {
	left := 1
	right := x
	for left <= right {
		mid := (left + right) / 2
		if mid == x/mid {
			return mid
		} else if mid < x/mid {
			left = mid + 1
		} else {
			right = mid - 1
		}
	}
	if left * left <= x{
		return left
	}else {
		return left-1
	}
}

// 暴力法:遍历
func mySqrt(x int) int {
	result := 0
	for i := 1; i <= x/i; i++ {
		if i*i == x {
			return i
		}
		result = i
	}
	return result
}

70.爬楼梯(3)

  • 题目

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
注意:给定 n 是一个正整数。
示例 1: 输入: 2 输出: 2 解释: 有两种方法可以爬到楼顶。 
1.  1 阶 + 1 阶
2.  2 阶
示例 2: 输入: 3 输出: 3 解释: 有三种方法可以爬到楼顶。
1.  1 阶 + 1 阶 + 1 阶
2.  1 阶 + 2 阶
3.  2 阶 + 1 阶
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 递归 O(n) O(n)
02 动态规划 O(n) O(n)
03(最优) 斐波那契 O(n) O(1)
// 递归
var arr []int

func climbStairs(n int) int {
	arr = make([]int, n+1)
	return climbStart(0, n)
}

func climbStart(i, n int) int {
	if i > n {
		return 0
	}
	if i == n {
		return 1
	}
	if arr[i] > 0 {
		return arr[i]
	}
	arr[i] = climbStart(i+1, n) + climbStart(i+2, n)
	return arr[i]
}

// 动态规划
func climbStairs(n int) int {
	if n == 1 {
		return 1
	}
	if n == 2 {
		return 2
	}
	dp := make([]int, n+1)
	dp[1] = 1
	dp[2] = 2
	for i := 3; i <= n; i++ {
		dp[i] = dp[i-1] + dp[i-2]
	}
	return dp[n]
}

// 斐波那契
func climbStairs(n int) int {
	if n == 1 {
		return 1
	}
	first := 1
	second := 2
	for i := 3; i <= n; i++ {
		third := first + second
		first = second
		second = third
	}
	return second
}

83.删除排序链表中的重复元素(3)

  • 题目

给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。
示例 1:输入: 1->1->2 输出: 1->2
示例 2:输入: 1->1->2->3->3 输出: 1->2->3
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01( 最优) 直接法 O(n) O(1)
02 递归法 O(n) O(1)
03 双指针法 O(n) O(1)
// 直接法
func deleteDuplicates(head *ListNode) *ListNode {
	if head == nil {
		return nil
	}
	temp := head
	for temp.Next != nil {
		if temp.Val == temp.Next.Val {
			temp.Next = temp.Next.Next
		} else {
			temp = temp.Next
		}
	}
	return head
}

// 递归法
func deleteDuplicates(head *ListNode) *ListNode {
	if head == nil || head.Next == nil{
		return head
	}
	head.Next = deleteDuplicates(head.Next)
	if head.Val == head.Next.Val{
		head = head.Next
	}
	return head
}

// 双指针法
func deleteDuplicates(head *ListNode) *ListNode {
	if head == nil || head.Next == nil{
		return head
	}
	p := head
	q := head.Next
	for p.Next != nil{
		if p.Val == q.Val{
			if q.Next == nil{
				p.Next = nil
			}else {
				p.Next = q.Next
				q = q.Next
			}
		}else {
			p = p.Next
			q = q.Next
		}
	}
	return head
}

88.合并两个有序数组(3)

  • 题目

给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组。
说明:
    初始化 nums1 和 nums2 的元素数量分别为 m 和 n。
    你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。
示例:输入: nums1 = [1,2,3,0,0,0], m = 3 nums2 = [2,5,6],       n = 3
输出: [1,2,2,3,5,6]
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 合并后排序 O(nlog(n)) O(1)
02(最优) 双指针法 O(n) O(1)
03 拷贝后插入 O(n) O(n)
// 合并后排序
func merge(nums1 []int, m int, nums2 []int, n int) {
	nums1 = nums1[:m]
	nums1 = append(nums1, nums2[:n]...)
	sort.Ints(nums1)
}

// 双指针法
func merge(nums1 []int, m int, nums2 []int, n int) {
	for m > 0 && n > 0 {
		if nums1[m-1] < nums2[n-1] {
			nums1[m+n-1] = nums2[n-1]
			n--
		} else {
			nums1[m+n-1] = nums1[m-1]
			m--
		}
	}
	if m == 0 && n > 0 {
		for n > 0 {
			nums1[n-1] = nums2[n-1]
			n--
		}
	}
}

// 拷贝后插入
func merge(nums1 []int, m int, nums2 []int, n int) {
	temp := make([]int, m)
	copy(temp, nums1)

	if n == 0 {
		return
	}
	first, second := 0, 0
	for i := 0; i < len(nums1); i++ {
		if second >= n {
			nums1[i] = temp[first]
			first++
			continue
		}
		if first >= m {
			nums1[i] = nums2[second]
			second++
			continue
		}
		if temp[first] < nums2[second] {
			nums1[i] = temp[first]
			first++
		} else {
			nums1[i] = nums2[second]
			second++
		}
	}
}

100.相同的树(2)

  • 题目

给定两个二叉树,编写一个函数来检验它们是否相同。
如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。
示例 1:
输入:       1         1
          / \       / \
         2   3     2   3
        [1,2,3],   [1,2,3]
输出: true
示例 2:
输入:      1          1
          /           \
         2             2
        [1,2],     [1,null,2]
输出: false
示例 3:
输入:       1         1
          / \       / \
         2   1     1   2
        [1,2,1],   [1,1,2]
输出: false
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 递归(深度优先) O(n) O(log(n))
02 层序遍历(宽度优先) O(n) O(log(n))
// 递归(深度优先)
func isSameTree(p *TreeNode, q *TreeNode) bool {
	if p == nil && q == nil {
		return true
	}

	if p == nil || q == nil {
		return false
	}

	return p.Val == q.Val && isSameTree(p.Left, q.Left) &&
		isSameTree(p.Right, q.Right)
}

// 层序遍历(宽度优先)
func isSameTree(p *TreeNode, q *TreeNode) bool {
	if p == nil && q == nil {
		return true
	}
	if p == nil || q == nil {
		return false
	}

	var queueP, queueQ []*TreeNode
	if p != nil {
		queueP = append(queueP, p)
		queueQ = append(queueQ, q)
	}

	for len(queueP) > 0 && len(queueQ) > 0 {
		tempP := queueP[0]
		queueP = queueP[1:]

		tempQ := queueQ[0]
		queueQ = queueQ[1:]

		if tempP.Val != tempQ.Val {
			return false
		}

		if (tempP.Left != nil && tempQ.Left == nil) ||
			(tempP.Left == nil && tempQ.Left != nil) {
			return false
		}
		if tempP.Left != nil {
			queueP = append(queueP, tempP.Left)
			queueQ = append(queueQ, tempQ.Left)
		}

		if (tempP.Right != nil && tempQ.Right == nil) ||
			(tempP.Right == nil && tempQ.Right != nil) {
			return false
		}
		if tempP.Right != nil {
			queueP = append(queueP, tempP.Right)
			queueQ = append(queueQ, tempQ.Right)
		}
	}
	return true
}

0001-0100-Medium

2.两数相加(2)

  • 题目

给出两个 非空 的链表用来表示两个非负的整数。
其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
您可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例:输入:(2 -> 4 -> 3) + (5 -> 6 -> 4) 输出:7 -> 0 -> 8
原因:342 + 465 = 807
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 遍历 O(n) O(n)
02 递归 O(n) O(n)
func addTwoNumbers(l1 *ListNode, l2 *ListNode) *ListNode {
	res := &ListNode{}
	cur := res
	carry := 0
	for l1 != nil || l2 != nil || carry > 0 {
		sum := carry
		if l1 != nil {
			sum += l1.Val
			l1 = l1.Next
		}
		if l2 != nil {
			sum += l2.Val
			l2 = l2.Next
		}
		carry = sum / 10 // 进位
		cur.Next = &ListNode{Val: sum % 10}
		cur = cur.Next
	}
	return res.Next
}

#
func addTwoNumbers(l1 *ListNode, l2 *ListNode) *ListNode {
	if l1 == nil && l2 == nil {
		return nil
	}
	if l1 == nil {
		return l2
	}
	if l2 == nil {
		return l1
	}
	sum := l1.Val + l2.Val
	res := &ListNode{Val: sum % 10}
	if sum >= 10 {
		l1.Next = addTwoNumbers(l1.Next, &ListNode{Val: 1})
	}
	res.Next = addTwoNumbers(l1.Next, l2.Next)
	return res
}

3.无重复字符的最长子串(4)

  • 题目

给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:输入: "abcabcbb"输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:输入: "bbbbb" 输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:输入: "pwwkew" 输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
     请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
同剑指offer面试题48.最长不含重复字符的子字符串
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 双指针 O(n) O(1)
02 双指针-内置函数 O(n^2) O(1)
03 哈希辅助-双指针 O(n) O(1)
04 动态规划 O(n) O(n)
05 双指针 O(n) O(1)
func lengthOfLongestSubstring(s string) int {
	arr := [256]int{}
	for i := range arr {
		arr[i] = -1
	}
	max, j := 0, 0
	for i := 0; i < len(s); i++ {
		if arr[s[i]] >= j {
			j = arr[s[i]] + 1
		} else if i+1-j > max {
			max = i + 1 - j
		}
		arr[s[i]] = i
	}
	return max
}

# 2
func lengthOfLongestSubstring(s string) int {
	max, j := 0, 0
	for i := 0; i < len(s); i++ {
		index := strings.Index(s[j:i], string(s[i]))
		if index == -1 {
			continue
		}
		if i-j > max {
			max = i - j
		}
		j = j + index + 1
	}
	if len(s)-j > max {
		max = len(s) - j
	}
	return max
}

# 3
func lengthOfLongestSubstring(s string) int {
	m := make(map[uint8]int)
	max, j := 0, 0
	for i := 0; i < len(s); i++ {
		if v, ok := m[s[i]]; ok && v >= j {
			j = v + 1
		} else if i+1-j > max {
			max = i + 1 - j
		}
		m[s[i]] = i
	}
	return max
}

# 4
func lengthOfLongestSubstring(s string) int {
	if len(s) < 1 {
		return 0
	}
	dp := make([]int, len(s))
	dp[0] = 1
	res := 1
	m := make(map[byte]int)
	m[s[0]] = 0
	for i := 1; i < len(s); i++ {
		index := -1
		if value, ok := m[s[i]]; ok {
			index = value
		}
		if i-index > dp[i-1] {
			dp[i] = dp[i-1] + 1
		} else {
			dp[i] = i - index
		}
		m[s[i]] = i
		if dp[i] > res {
			res = dp[i]
		}
	}
	return res
}

# 5
func lengthOfLongestSubstring(s string) int {
	arr := [256]int{}
	for i := range arr {
		arr[i] = -1
	}
	res, j := 0, -1
	for i := 0; i < len(s); i++ {
		if arr[s[i]] > j { // 出现重复了,更新下标
			j = arr[s[i]]
		} else {
			res = max(res, i-j) // 没有重复,更新长度
		}
		arr[s[i]] = i
	}
	return res
}

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

5.最长回文子串(5)

  • 题目

给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
示例 1:输入: "babad"输出: "bab" 注意: "aba" 也是一个有效答案。
示例 2:输入: "cbbd" 输出: "bb"
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 动态规划 O(n^2) O(n^2)
02 中心扩展 O(n^2) O(1)
03 暴力法 O(n^3) O(1)
04 Manacher算法 O(n^2) O(n)
05 Manacher算法 O(n) O(n)
// dp(l,r)=dp(l+1,r−1)&&(s[l]==s[r])
// dp[l,r]:字符串s从索引l到r的子串是否是回文串
func longestPalindrome(s string) string {
	if len(s) <= 1 {
		return s
	}
	dp := make([][]bool, len(s))
	start := 0
	max := 1
	for r := 0; r < len(s); r++ {
		dp[r] = make([]bool, len(s))
		dp[r][r] = true
		for l := 0; l < r; l++ {
			if s[l] == s[r] && (r-l <= 2 || dp[l+1][r-1] == true) {
				dp[l][r] = true
			} else {
				dp[l][r] = false
			}
			if dp[l][r] == true {
				if r-l+1 > max {
					max = r - l + 1
					start = l
				}
			}
		}
	}
	return s[start : start+max]
}

# 2
func longestPalindrome(s string) string {
	if len(s) <= 1 {
		return s
	}
	start := 0
	end := 0
	for i := 0; i < len(s); i++ {
		left1, right1 := find(s, i, i)
		left2, right2 := find(s, i, i+1)
		if right1-left1 > end-start {
			start, end = left1, right1
		}
		if right2-left2 > end-start {
			start, end = left2, right2
		}
	}
	return s[start : end+1]
}

func find(s string, left, right int) (int, int) {
	for ; 0 <= left && right < len(s) && s[left] == s[right]; left, right = left-1, right+1 {
	}
	return left + 1, right - 1
}

# 3
func longestPalindrome(s string) string {
	if len(s) <= 1 {
		return s
	}
	res := ""
	for i := 0; i < len(s); i++ {
		for j := i; j < len(s); j++ {
			str := s[i : j+1]
			if len(str) < len(res) && res != "" {
				continue
			}
			if judge(str) == true && len(res) < len(str) {
				res = str
			}
		}
	}
	return res
}

func judge(s string) bool {
	for i := 0; i < len(s)/2; i++ {
		if s[i] != s[len(s)-1-i] {
			return false
		}
	}
	return true
}

# 4
func longestPalindrome(s string) string {
	if len(s) <= 1 {
		return s
	}
	str := add(s)
	length := len(str)
	max := 1
	begin := 0
	for i := 0; i < length; i++ {
		curLength := search(str, i)
		if curLength > max {
			max = curLength
			begin = (i - max) / 2
		}
	}
	return s[begin : begin+max]
}

func search(s string, center int) int {
	i := center - 1
	j := center + 1
	step := 0
	for ; i >= 0 && j < len(s) && s[i] == s[j]; i, j = i-1, j+1 {
		step++
	}
	return step
}

func add(s string) string {
	var res []rune
	for _, v := range s {
		res = append(res, '#')
		res = append(res, v)
	}
	res = append(res, '#')
	return string(res)
}

#
func longestPalindrome(s string) string {
	if len(s) <= 1 {
		return s
	}
	str := add(s)
	length := len(str)
	temp := make([]int, length)
	maxRight := 0
	center := 0
	max := 1
	begin := 0
	for i := 0; i < length; i++ {
		if i < maxRight {
			mirror := 2*center - i
			temp[i] = min(maxRight-i, temp[mirror])
		}
		left := i - (1 + temp[i])
		right := i + (1 + temp[i])
		for left >= 0 && right < len(str) && str[left] == str[right] {
			temp[i]++
			left--
			right++
		}
		if i+temp[i] > maxRight {
			maxRight = i + temp[i]
			center = i
		}
		if temp[i] > max {
			max = temp[i]
			begin = (i - max) / 2
		}
	}
	return s[begin : begin+max]
}

func add(s string) string {
	var res []rune
	for _, v := range s {
		res = append(res, '#')
		res = append(res, v)
	}
	res = append(res, '#')
	return string(res)
}

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

6.Z字形变换(2)

  • 题目

将一个给定字符串根据给定的行数,以从上往下、从左到右进行 Z 字形排列。
比如输入字符串为 "LEETCODEISHIRING" 行数为 3 时,排列如下:
L   C   I   R
E T O E S I I G
E   D   H   N
之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:"LCIRETOESIIGEDHN"。
请你实现这个将字符串进行指定行数变换的函数:
string convert(string s, int numRows);
示例 1:输入: s = "LEETCODEISHIRING", numRows = 3 输出: "LCIRETOESIIGEDHN"
示例 2:输入: s = "LEETCODEISHIRING", numRows = 4 输出: "LDREOEIIECIHNTSG"
解释:
L     D     R
E   O E   I I
E C   I H   N
T     S     G
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 遍历 O(n) O(n)
02 遍历 O(n) O(n)
func convert(s string, numRows int) string {
	if numRows == 1 {
		return s
	}
	arr := []rune(s)
	total := numRows*2 - 2
	res := make([]string, numRows)
	for i := 0; i < len(arr); i++ {
		index := i % total
		if index < numRows {
			res[index] = res[index] + string(arr[i])
		} else {
			res[total-index] = res[total-index] + string(arr[i])
		}
	}
	return strings.Join(res, "")
}

#
func convert(s string, numRows int) string {
	if numRows == 1 {
		return s
	}
	arr := []rune(s)
	res := make([]string, numRows)
	flag := -1
	index := 0
	for i := 0; i < len(arr); i++ {
		res[index] = res[index] + string(arr[i])
		if index == 0 || index == numRows-1 {
			flag = -flag
		}
		index = index + flag
	}
	return strings.Join(res, "")
}

8.字符串转换整数 (atoi)(3)

  • 题目

请你来实现一个 atoi 函数,使其能将字符串转换成整数。
首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。接下来的转化规则如下:
   如果第一个非空字符为正或者负号时,则将该符号与之后面尽可能多的连续数字字符组合起来,形成一个有符号整数。
   假如第一个非空字符是数字,则直接将其与之后连续的数字字符组合起来,形成一个整数。
   该字符串在有效的整数部分之后也可能会存在多余的字符,那么这些字符可以被忽略,它们对函数不应该造成影响。
注意:假如该字符串中的第一个非空格字符不是一个有效整数字符、字符串为空或字符串仅包含空白字符时,
则你的函数不需要进行转换,即无法进行有效转换。
在任何情况下,若函数不能进行有效的转换时,请返回 0 。
提示:
    本题中的空白字符只包括空格字符 ' ' 。
    假设我们的环境只能存储 32 位大小的有符号整数,那么其数值范围为 [−231,  231 − 1]。
    如果数值超过这个范围,请返回  INT_MAX (231 − 1) 或 INT_MIN (−231) 。
示例 1:输入: "42" 输出: 42
示例 2:输入: "   -42" 输出: -42
解释: 第一个非空白字符为 '-', 它是一个负号。
     我们尽可能将负号与后面所有连续出现的数字组合起来,最后得到 -42 。
示例 3:输入: "4193 with words" 输出: 4193
解释: 转换截止于数字 '3' ,因为它的下一个字符不为数字。
示例 4:输入: "words and 987" 输出: 0
解释: 第一个非空字符是 'w', 但它不是数字或正、负号。
     因此无法执行有效的转换。
示例 5:输入: "-91283472332" 输出: -2147483648
解释: 数字 "-91283472332" 超过 32 位有符号整数范围。 
     因此返回 INT_MIN (−231) 。
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 遍历 O(n) O(n)
02 正则 O(n) O(n)
03 遍历 O(n) O(n)
func myAtoi(str string) int {
	i := 0
	for i < len(str) && str[i] == ' ' {
		i++
	}
	str = str[i:]
	arr := make([]byte, 0)
	isFlag := byte(' ')
	for j := 0; j < len(str); j++ {
		if str[j] >= '0' && str[j] <= '9' {
			arr = append(arr, str[j])
		} else {
			if len(arr) > 0 {
				break
			}
			if str[j] != ' ' && str[j] != '+' && str[j] != '-' {
				return 0
			}
			if isFlag != ' ' {
				return 0
			}
			isFlag = str[j]
		}
	}
	res := 0
	for i := 0; i < len(arr); i++ {
		value := int(arr[i] - '0')
		res = res*10 + value
		if isFlag == '-' {
			if -1*res < math.MinInt32 {
				return math.MinInt32
			}
		} else if isFlag == ' ' || isFlag == '+' {
			if res > math.MaxInt32 {
				return math.MaxInt32
			}
		}
	}
	if isFlag == '-' {
		return -1 * res
	}
	return res
}

#
func myAtoi(str string) int {
	re := regexp.MustCompile(`^[+-]?\d+`)
	arrS := re.FindAllString(strings.Trim(str, " "), -1)
	if len(arrS) == 0{
		return 0
	}
	arr := arrS[0]
	res := 0
	isFlag := byte(' ')
	if !(arr[0] >= '0' && arr[0] <= '9') {
		isFlag = arr[0]
		arr = arr[1:]
	}
	for i := 0; i < len(arr); i++ {
		value := int(arr[i] - '0')
		if isFlag == '-' {
			if res > 214748364 || (res==214748364 && value >= 8) {
				return math.MinInt32
			}
		} else if isFlag == ' ' || isFlag == '+' {
			if res > 214748364 || (res==214748364 && value >= 7) {
				return math.MaxInt32
			}
		}
		res = res*10 + value
	}
	if isFlag == '-' {
		return -1 * res
	}
	return res
}

#
func myAtoi(str string) int {
	str = strings.TrimSpace(str)
	result := 0
	flag := 1
	for i, v := range str {
		if v >= '0' && v <= '9' {
			result = result*10 + int(v-'0')
		} else if v == '-' && i == 0 {
			flag = -1
		} else if v == '+' && i == 0 {
			flag = 1
		} else {
			break
		}
		if result > math.MaxInt32 {
			if flag == -1 {
				return math.MinInt32
			}
			return math.MaxInt32
		}
	}
	return flag * result
}

11.盛最多水的容器(2)

  • 题目

给你 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) 。
在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。
找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
说明:你不能倾斜容器,且 n 的值至少为 2。
图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。
示例:输入:[1,8,6,2,5,4,8,3,7] 输出:49
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 遍历-双指针 O(n) O(1)
02 遍历-暴力法 O(n^2) O(1)
func maxArea(height []int) int {
	i := 0
	j := len(height) - 1
	res := 0
	for i < j {
		area := (j - i) * min(height[i], height[j])
		if area > res {
			res = area
		}
		// 移动较小的指针,尝试获取更大的面积
		if height[i] > height[j] {
			j--
		} else {
			i++
		}
	}
	return res
}

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

#
func maxArea(height []int) int {
	res := 0
	for i := 0; i < len(height); i++ {
		for j := i + 1; j < len(height); j++ {
			area := (j - i) * min(height[i], height[j])
			if area > res {
				res = area
			}
		}
	}
	return res
}

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

12.整数转罗马数字(2)

  • 题目

罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。
字符          数值
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。
给定一个整数,将其转为罗马数字。输入确保在 1 到 3999 的范围内。
示例 1:输入: 3输出: "III"
示例 2:输入: 4 输出: "IV"
示例 3:输入: 9 输出: "IX"
示例 4:输入: 58 输出: "LVIII"
解释: L = 50, V = 5, III = 3.
示例 5:输入: 1994 输出: "MCMXCIV"
解释: M = 1000, CM = 900, XC = 90, IV = 4.
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 遍历 O(log(n)) O(1)
02 枚举 O(1) O(1)
func intToRoman(num int) string {
	m := map[int]string{
		1:    "I",
		4:    "IV",
		5:    "V",
		9:    "IX",
		10:   "X",
		40:   "XL",
		50:   "L",
		90:   "XC",
		100:  "C",
		400:  "CD",
		500:  "D",
		900:  "CM",
		1000: "M",
	}
	arr := []int{1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1}
	result := ""
	for i := 0; i < len(arr); i++ {
		if num == 0 {
			break
		}
		value := num / arr[i]
		for j := 0; j < value; j++ {
			result = result + m[arr[i]]
		}
		num = num - value*arr[i]
	}
	return result
}

#
func intToRoman(num int) string {
	res := ""
	arr1 := []string{"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"}
	arr2 := []string{"", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"}
	arr3 := []string{"", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"}
	arr4 := []string{"", "M", "MM", "MMM"}
	res = arr4[num/1000] + arr3[num%1000/100] + arr2[num%100/10] + arr1[num%10]
	return res
}

15.三数之和(2)

  • 题目

给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?
请你找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例:
给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
  [-1, 0, 1],
  [-1, -1, 2]
]
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 双指针 O(n^2) O(n^2)
02 哈希辅助 O(n^2) O(n^2)
func threeSum(nums []int) [][]int {
	res := make([][]int, 0)
	sort.Ints(nums)
	for i := 0; i < len(nums)-1; i++ {
		target := 0 - nums[i]
		left := i + 1
		right := len(nums) - 1
		if nums[i] > 0 || nums[i]+nums[left] > 0 {
			break
		}
		if i > 0 && nums[i] == nums[i-1] {
			continue
		}
		for left < right {
			if left > i+1 && nums[left] == nums[left-1] {
				left++
				continue
			}
			if right < len(nums)-2 && nums[right] == nums[right+1] {
				right--
				continue
			}
			if nums[left]+nums[right] > target {
				right--
			} else if nums[left]+nums[right] < target {
				left++
			} else {
				res = append(res, []int{nums[i], nums[left], nums[right]})
				left++
				right--
			}
		}
	}
	return res
}

#
func threeSum(nums []int) [][]int {
	res := make([][]int, 0)
	m := make(map[[2]int]int)
	p := make(map[int]int)
	sort.Ints(nums)
	for k, v := range nums {
		p[v] = k
	}
	for i := 0; i < len(nums); i++ {
		for j := i + 1; j < len(nums); j++ {
			if j != i+1 && nums[j] == nums[j-1] {
				continue
			}
			sum := nums[i] + nums[j]
			if sum > 0 {
				break
			}
			if value, ok := p[-sum]; ok && value > j {
				if _, ok2 := m[[2]int{nums[i], nums[j]}]; !ok2 {
					res = append(res, []int{nums[i], nums[j], 0 - nums[i] - nums[j]})
					m[[2]int{nums[i], nums[j]}] = 1
				}
			}
		}
	}
	return res
}

16.最接近的三数之和(2)

  • 题目

给定一个包括 n 个整数的数组 nums 和 一个目标值 target。
找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。
示例:输入:nums = [-1,2,1,-4], target = 1 输出:2
解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。
提示:
    3 <= nums.length <= 10^3
    -10^3 <= nums[i] <= 10^3
    -10^4 <= target <= 10^4
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 双指针 O(n^2) O(1)
02 暴力法 O(n^3) O(1)
func threeSumClosest(nums []int, target int) int {
	sort.Ints(nums)
	res := nums[0] + nums[1] + nums[2]
	for i := 0; i < len(nums); i++ {
		left := i + 1
		right := len(nums) - 1
		for left < right {
			sum := nums[i] + nums[left] + nums[right]
			if sum > target {
				right--
			} else if sum < target {
				left++
			} else {
				return target
			}
			if abs(sum, target) < abs(res, target) {
				res = sum
			}
		}
	}
	return res
}

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

#
func threeSumClosest(nums []int, target int) int {
	res := nums[0] + nums[1] + nums[2]
	for i := 0; i < len(nums); i++ {
		for j := i + 1; j < len(nums); j++ {
			for k := j + 1; k < len(nums); k++ {
				sum := nums[i] + nums[j] + nums[k]
				if abs(sum, target) < abs(res, target) {
					res = sum
				}
			}
		}
	}
	return res
}

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

17.电话号码的字母组合(2)

  • 题目

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
示例:输入:"23"输出:["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].
说明:尽管上面的答案是按字典序排列的,但是你可以任意选择答案输出的顺序。
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 遍历 O(4^n) O(4^n)
02 递归-回溯 O(4^n) O(4^n)
func letterCombinations(digits string) []string {
	if len(digits) == 0 {
		return nil
	}
	arr := []string{"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"}
	res := []string{""}
	for i := 0; i < len(digits); i++ {
		length := len(res)
		for j := 0; j < length; j++ {
			for k := 0; k < len(arr[digits[i]-'0']); k++ {
				res = append(res, res[j]+string(arr[digits[i]-'0'][k]))
			}
		}
		res = res[length:]
	}
	return res
}

#
var res []string
var arr = []string{"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"}

func letterCombinations(digits string) []string {
	if len(digits) == 0 {
		return nil
	}
	res = make([]string, 0)
	dfs(digits, 0, "")
	return res
}

func dfs(digits string, index int, str string) {
	if index == len(digits) {
		res = append(res, str)
		return
	}
	for i := 0; i < len(arr[digits[index]-'0']); i++ {
		dfs(digits, index+1, str+string(arr[digits[index]-'0'][i]))
	}
}

18.四数之和(3)

  • 题目

给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,
使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。
注意:答案中不可以包含重复的四元组。
示例:给定数组 nums = [1, 0, -1, 0, -2, 2],和 target = 0。
满足要求的四元组集合为:
[
  [-1,  0, 0, 1],
  [-2, -1, 1, 2],
  [-2,  0, 0, 2]
]
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 双指针 O(n^3) O(n^3)
02 哈希辅助 O(n^3) O(n^3)
03 全排列+递归 O(n^3) O(n^3)
func fourSum(nums []int, target int) [][]int {
	sort.Ints(nums)
	res := make([][]int, 0)
	for i := 0; i < len(nums); i++ {
		if i > 0 && nums[i] == nums[i-1] {
			continue
		}
		for j := i + 1; j < len(nums); j++ {
			if j > i+1 && nums[j] == nums[j-1] {
				continue
			}
			temp := target - nums[i] - nums[j]
			left := j + 1
			right := len(nums) - 1
			for left < right {
				if left > j+1 && nums[left] == nums[left-1] {
					left++
					continue
				}
				if right < len(nums)-2 && nums[right] == nums[right+1] {
					right--
					continue
				}
				if nums[left]+nums[right] > temp {
					right--
				} else if nums[left]+nums[right] < temp {
					left++
				} else {
					res = append(res, []int{nums[i], nums[j], nums[left], nums[right]})
					left++
					right--
				}
			}
		}
	}
	return res
}

#
func fourSum(nums []int, target int) [][]int {
	m := make(map[[3]int]int)
	p := make(map[int]int)
	sort.Ints(nums)
	for k, v := range nums {
		p[v] = k
	}
	res := make([][]int, 0)
	for i := 0; i < len(nums); i++ {
		for j := i + 1; j < len(nums); j++ {
			for k := j + 1; k < len(nums); k++ {
				sum := nums[i] + nums[j] + nums[k]
				if value, ok := p[target-sum]; ok && value > k {
					if _, ok2 := m[[3]int{nums[i], nums[j], nums[k]}]; !ok2 {
						res = append(res, []int{nums[i], nums[j], nums[k], target - nums[i] - nums[j] - nums[k]})
						m[[3]int{nums[i], nums[j], nums[k]}] = 1
					}
				}
			}
		}
	}
	return res
}

#
var res [][]int

func fourSum(nums []int, target int) [][]int {
	sort.Ints(nums)
	res = make([][]int, 0)
	dfs(nums, target, []int{}, 0)
	return res
}

func dfs(nums []int, target int, arr []int, level int) {
	if len(arr) == 4 {
		sum := 0
		for i := 0; i < len(arr); i++ {
			sum = sum + arr[i]
		}
		if sum == target {
			tempArr := make([]int, len(arr))
			copy(tempArr, arr)
			res = append(res, tempArr)
		}
		return
	}
	prev := math.MaxInt32
	for i := level; i < len(nums); i++ {
		if nums[i] != prev {
			prev = nums[i]
			arr = append(arr, nums[i])
			dfs(nums, target, arr, i+1)
			arr = arr[:len(arr)-1]
		}
	}
}

19.删除链表的倒数第N个节点(3)

  • 题目

给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:给定的 n 保证是有效的。
进阶:你能尝试使用一趟扫描实现吗?
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 遍历 O(n) O(1)
02 快慢指针 O(n) O(1)
03 递归 O(n) O(n)
func removeNthFromEnd(head *ListNode, n int) *ListNode {
	temp := &ListNode{Next: head}
	cur := temp
	total := 0
	for cur.Next != nil {
		cur = cur.Next
		total++
	}
	cur = temp
	count := 0
	for cur.Next != nil {
		if total-n == count {
			cur.Next = cur.Next.Next
			break
		}
		cur = cur.Next
		count++
	}
	return temp.Next
}

#
func removeNthFromEnd(head *ListNode, n int) *ListNode {
	temp := &ListNode{Next: head}
	fast, slow := temp, temp
	for i := 0; i < n; i++ {
		fast = fast.Next
	}
	for fast.Next != nil {
		fast = fast.Next
		slow = slow.Next
	}
	slow.Next = slow.Next.Next
	return temp.Next
}

#
var count int

func removeNthFromEnd(head *ListNode, n int) *ListNode {
	if head == nil {
		count = 0
		return nil
	}
	head.Next = removeNthFromEnd(head.Next, n)
	count = count + 1
	if count == n {
		return head.Next
	}
	return head
}

22.括号生成(3)

  • 题目

数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。
示例:输入:n = 3
输出:[
       "((()))",
       "(()())",
       "(())()",
       "()(())",
       "()()()"
     ]
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 全排列-递归 O(4^n/n^(1/2)) O(4^n/n^(1/2))
02 动态规划 O(4^n/n^(1/2)) O(4^n/n^(1/2))
03 广度优先搜索 O(4^n/n^(1/2)) O(4^n/n^(1/2))
var res []string

func generateParenthesis(n int) []string {
	res = make([]string, 0)
	dfs(0, 0, n, "")
	return res
}

func dfs(left, right, max int, str string) {
	if left == right && left == max {
		res = append(res, str)
		return
	}
	if left < max {
		dfs(left+1, right, max, str+"(")
	}
	if right < left {
		dfs(left, right+1, max, str+")")
	}
}

#
/*
dp[i]表示n=i时括号的组合
dp[i]="(" + dp[j] + ")"+dp[i-j-1] (j<i)
dp[0] = ""
*/
func generateParenthesis(n int) []string {
	dp := make([][]string, n+1)
	dp[0] = make([]string, 0)
	if n == 0 {
		return dp[0]
	}
	dp[0] = append(dp[0], "")
	for i := 1; i <= n; i++ {
		dp[i] = make([]string, 0)
		for j := 0; j < i; j++ {
			for _, a := range dp[j] {
				for _, b := range dp[i-j-1] {
					str := "(" + a + ")" + b
					dp[i] = append(dp[i], str)
				}
			}
		}
	}
	return dp[n]
}

#
type Node struct {
	str   string
	left  int
	right int
}

func generateParenthesis(n int) []string {
	res := make([]string, 0)
	if n == 0 {
		return res
	}
	queue := make([]*Node, 0)
	queue = append(queue, &Node{
		str:   "",
		left:  n,
		right: n,
	})
	for len(queue) > 0 {
		node := queue[0]
		queue = queue[1:]
		if node.left == 0 && node.right == 0 {
			res = append(res, node.str)
		}
		if node.left > 0 {
			queue = append(queue, &Node{
				str:   node.str + "(",
				left:  node.left - 1,
				right: node.right,
			})
		}
		if node.right > 0 && node.left < node.right {
			queue = append(queue, &Node{
				str:   node.str + ")",
				left:  node.left,
				right: node.right - 1,
			})
		}
	}
	return res
}

24.两两交换链表中的节点(2)

  • 题目

给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
示例:给定 1->2->3->4, 你应该返回 2->1->4->3.
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 遍历 O(n) O(1)
02 递归 O(n) O(n)
func swapPairs(head *ListNode) *ListNode {
	temp := &ListNode{Next: head}
	prev := temp
	for head != nil && head.Next != nil {
		first, second := head, head.Next
		prev.Next = second
		first.Next, second.Next = second.Next, first
		prev, head = first, first.Next
	}
	return temp.Next
}

#
func swapPairs(head *ListNode) *ListNode {
	if head == nil || head.Next == nil {
		return head
	}
	first, second := head, head.Next
	first.Next, second.Next = swapPairs(second.Next), first
	return second
}

29.两数相除(2)

  • 题目

给定两个整数,被除数 dividend 和除数 divisor。将两数相除,要求不使用乘法、除法和 mod 运算符。
返回被除数 dividend 除以除数 divisor 得到的商。
整数除法的结果应当截去(truncate)其小数部分,
例如:truncate(8.345) = 8 以及 truncate(-2.7335) = -2
示例 1:输入: dividend = 10, divisor = 3输出: 3
解释: 10/3 = truncate(3.33333..) = truncate(3) = 3
示例 2:输入: dividend = 7, divisor = -3 输出: -2
解释: 7/-3 = truncate(-2.33333..) = -2
提示:
    被除数和除数均为 32 位有符号整数。
    除数不为 0。
    假设我们的环境只能存储 32 位有符号整数,其数值范围是 [−2^31,  2^31 − 1]。
    本题中,如果除法结果溢出,则返回 2^31 − 1。
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 遍历 O(log(n)) O(1)
02 计算 O(1) O(1)
func divide(dividend int, divisor int) int {
	if divisor == 0 || dividend == 0 {
		return 0
	}
	if divisor == 1 {
		return dividend
	}
	flag, count := 1, 1
	if dividend < 0 {
		flag = -flag
		dividend = -dividend
	}
	if divisor < 0 {
		flag = -flag
		divisor = -divisor
	}
	a, b, c := dividend, divisor, 0
	temp := b
	for a-b >= 0 {
		for a-b >= 0 {
			a = a - b
			c = c + count
			b = b + b
			count = count + count
		}
		b = temp
		count = 1
	}
	if c > math.MaxInt32 {
		return math.MaxInt32
	}
	if flag < 0 {
		return -c
	}
	return c
}

#
func divide(dividend int, divisor int) int {
	res := dividend / divisor
	if res > math.MaxInt32 {
		return math.MaxInt32
	}
	return res
}

31.下一个排列(2)

  • 题目

实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。
如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。
必须原地修改,只允许使用额外常数空间。
以下是一些例子,输入位于左侧列,其相应输出位于右侧列。
1,2,3 → 1,3,2
3,2,1 → 1,2,3
1,1,5 → 1,5,1
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 遍历 O(n) O(1)
02 遍历 O(n) O(1)
func nextPermutation(nums []int) {
	n := len(nums)
	left := n - 2
	// 以12385764为例,从后往前找到5<7 的升序情况,目标值为左边的数5
	for left >= 0 && nums[left] >= nums[left+1] {
		left--
	}
	if left == -1 {
		sort.Ints(nums)
		return
	}
	right := n - 1
	// 从后往前,找到第一个大于目标值的数,如6>5,然后交换
	for right >= 0 && nums[right] <= nums[left] {
		right--
	}
	nums[left], nums[right] = nums[right], nums[left]
	count := 0
	// 后面是降序状态,让它变为升序
	for i := left + 1; i <= (left+1+n-1)/2; i++ {
		nums[i], nums[n-1-count] = nums[n-1-count], nums[i]
		count++
	}
}

# 2
func nextPermutation(nums []int) {
	n := len(nums)
	left := n - 2
	// 以12385764为例,从后往前找到5<7 的升序情况,目标值为左边的数5
	for left >= 0 && nums[left] >= nums[left+1] {
		left--
	}
	if left >= 0 { // 存在升序的情况
		right := n - 1
		// 从后往前,找到第一个大于目标值的数,如6>5,然后交换
		for right >= 0 && nums[right] <= nums[left] {
			right--
		}
		nums[left], nums[right] = nums[right], nums[left]
	}
	reverse(nums, left+1, n-1)
}

func reverse(nums []int, left, right int) {
	for left < right {
		nums[left], nums[right] = nums[right], nums[left]
		left++
		right--
	}
}

33.搜索旋转排序数组(2)

  • 题目

假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。
搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。
你可以假设数组中不存在重复的元素。
你的算法时间复杂度必须是 O(log n) 级别。
示例 1:输入: nums = [4,5,6,7,0,1,2], target = 0 输出: 4
示例 2:输入: nums = [4,5,6,7,0,1,2], target = 3 输出: -1
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 二分查找 O(log(n)) O(1)
02 遍历 O(n) O(1)
func search(nums []int, target int) int {
	left, right := 0, len(nums)-1
	for left <= right {
		mid := left + (right-left)/2
		if nums[mid] == target {
			return mid
		}
		if nums[left] <= nums[mid] {
			if nums[left] <= target && target < nums[mid] {
				right = mid - 1
			} else {
				left = mid + 1
			}
		} else {
			if nums[mid] < target && target <= nums[right] {
				left = mid + 1
			} else {
				right = mid - 1
			}
		}
	}
	return -1
}

#
func search(nums []int, target int) int {
	for i := 0; i < len(nums); i++{
		if nums[i] == target{
			return i
		}
	}
	return -1
}

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

  • 题目

给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。
你的算法时间复杂度必须是 O(log n) 级别。
如果数组中不存在目标值,返回 [-1, -1]。
示例 1:输入: nums = [5,7,7,8,8,10], target = 8 输出: [3,4]
示例 2:输入: nums = [5,7,7,8,8,10], target = 6 输出: [-1,-1]
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 双指针 O(n) O(1)
02 遍历 O(n) O(1)
03 二分查找 O(log(n)) O(1)
04 二分查找 O(log(n)) O(1)
func searchRange(nums []int, target int) []int {
	left := 0
	right := len(nums) - 1
	for left <= right {
		if nums[left] != target {
			if target > nums[left] {
				left++
			}
		}
		if nums[right] != target {
			if target < nums[right] {
				right--
			}
		}
		if left < len(nums) && right >= 0 &&
			nums[left] == nums[right] && nums[left] == target {
			break
		}
	}
	if right < left {
		return []int{-1, -1}
	}
	return []int{left, right}
}

#
func searchRange(nums []int, target int) []int {
	left := -1
	right := -1
	for i := 0; i < len(nums); i++ {
		if nums[i] == target {
			right = i
		} else if nums[i] > target {
			break
		}
	}
	for i := len(nums) - 1; i >= 0; i-- {
		if nums[i] == target {
			left = i
		} else if nums[i] < target {
			break
		}
	}
	return []int{left, right}
}

# 3
func searchRange(nums []int, target int) []int {
	if len(nums) == 0 || nums[0] > target || nums[len(nums)-1] < target {
		return []int{-1, -1}
	}
	left := leftSearch(nums, target)
	right := rightSearch(nums, target)
	return []int{left, right}
}

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

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

#
func searchRange(nums []int, target int) []int {
	left := -1
	right := -1
	for i, j := 0, len(nums)-1; i <= j; {
		mid := i + (j-i)/2
		if nums[mid] < target {
			i = mid + 1
		} else if nums[mid] > target {
			j = mid - 1
		} else {
			for temp := mid; temp >= 0; temp-- {
				if target == nums[temp] {
					left = temp
				} else {
					break
				}
			}
			for temp := mid; temp < len(nums); temp++ {
				if target == nums[temp] {
					right = temp
				} else {
					break
				}
			}
			break
		}
	}
	return []int{left, right}
}

36.有效的数独(1)

  • 题目

判断一个 9x9 的数独是否有效。只需要根据以下规则,验证已经填入的数字是否有效即可。
    数字 1-9 在每一行只能出现一次。
    数字 1-9 在每一列只能出现一次。
    数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。
上图是一个部分填充的有效的数独。
数独部分空格内已填入了数字,空白格用 '.' 表示。
示例 1:输入:
[
  ["5","3",".",".","7",".",".",".","."],
  ["6",".",".","1","9","5",".",".","."],
  [".","9","8",".",".",".",".","6","."],
  ["8",".",".",".","6",".",".",".","3"],
  ["4",".",".","8",".","3",".",".","1"],
  ["7",".",".",".","2",".",".",".","6"],
  [".","6",".",".",".",".","2","8","."],
  [".",".",".","4","1","9",".",".","5"],
  [".",".",".",".","8",".",".","7","9"]
]
输出: true
示例 2:输入:
[
  ["8","3",".",".","7",".",".",".","."],
  ["6",".",".","1","9","5",".",".","."],
  [".","9","8",".",".",".",".","6","."],
  ["8",".",".",".","6",".",".",".","3"],
  ["4",".",".","8",".","3",".",".","1"],
  ["7",".",".",".","2",".",".",".","6"],
  [".","6",".",".",".",".","2","8","."],
  [".",".",".","4","1","9",".",".","5"],
  [".",".",".",".","8",".",".","7","9"]
]
输出: false
解释: 除了第一行的第一个数字从 5 改为 8 以外,空格内其他数字均与 示例1 相同。
     但由于位于左上角的 3x3 宫内有两个 8 存在, 因此这个数独是无效的。
说明:
    一个有效的数独(部分已被填充)不一定是可解的。
    只需要根据以上规则,验证已经填入的数字是否有效即可。
    给定数独序列只包含数字 1-9 和字符 '.' 。
    给定数独永远是 9x9 形式的。
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 遍历 O(1) O(1)
func isValidSudoku(board [][]byte) bool {
	var row, col, arr [9][9]int
	for i := 0; i < 9; i++ {
		for j := 0; j < 9; j++ {
			if board[i][j] != '.' {
				num := board[i][j] - '1'
				index := (i/3)*3 + j/3
				if row[i][num] == 1 || col[j][num] == 1 || arr[index][num] == 1 {
					return false
				}
				row[i][num] = 1
				col[j][num] = 1
				arr[index][num] = 1
			}
		}
	}
	return true
}

39.组合总和(2)

  • 题目

给定一个无重复元素的数组 candidates 和一个目标数 target ,
找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的数字可以无限制重复被选取。
说明:
    所有数字(包括 target)都是正整数。
    解集不能包含重复的组合。 
示例 1:输入: candidates = [2,3,6,7], target = 7, 所求解集为:
[
  [7],
  [2,2,3]
]
示例 2:输入: candidates = [2,3,5], target = 8, 所求解集为:
[
  [2,2,2,2],
  [2,3,3],
  [3,5]
]
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 递归 O(2^n) O(2^n)
02 递归 O(2^n) O(2^n)
var res [][]int

func combinationSum(candidates []int, target int) [][]int {
	res = make([][]int, 0)
	sort.Ints(candidates)
	dfs(candidates, target, []int{}, 0)
	return res
}

func dfs(candidates []int, target int, arr []int, index int) {
	if target == 0 {
		temp := make([]int, len(arr))
		copy(temp, arr)
		res = append(res, temp)
		return
	}
	if target < 0{
		return
	}
	for i := index; i < len(candidates); i++ {
		arr = append(arr, candidates[i])
		dfs(candidates, target-candidates[i], arr, i)
		arr = arr[:len(arr)-1]
	}
}

#
var res [][]int

func combinationSum(candidates []int, target int) [][]int {
	res = make([][]int, 0)
	sort.Ints(candidates)
	dfs(candidates, target, []int{}, 0)
	return res
}

func dfs(candidates []int, target int, arr []int, index int) {
	if target == 0 {
		temp := make([]int, len(arr))
		copy(temp, arr)
		res = append(res, temp)
		return
	}
	for i := index; i < len(candidates); i++ {
		if target < candidates[i] {
			return
		}
		dfs(candidates, target-candidates[i], append(arr, candidates[i]), i)
	}
}

40.组合总和II(2)

  • 题目

给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的每个数字在每个组合中只能使用一次。
说明:
    所有数字(包括目标数)都是正整数。
    解集不能包含重复的组合。 
示例 1:输入: candidates = [10,1,2,7,6,1,5], target = 8,
所求解集为:
[
  [1, 7],
  [1, 2, 5],
  [2, 6],
  [1, 1, 6]
]
示例 2:输入: candidates = [2,5,2,1,2], target = 5,
所求解集为:
[
  [1,2,2],
  [5]
]
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 递归 O(n!) O(n!)
02 递归 O(n!) O(n!)
var res [][]int

func combinationSum2(candidates []int, target int) [][]int {
	res = make([][]int, 0)
	sort.Ints(candidates)
	dfs(candidates, target, []int{}, 0)
	return res
}

func dfs(candidates []int, target int, arr []int, index int) {
	if target == 0 {
		temp := make([]int, len(arr))
		copy(temp, arr)
		res = append(res, temp)
		return
	}
	if target < 0 {
		return
	}
	for i := index; i < len(candidates); i++ {
		origin := i
		for i < len(candidates)-1 && candidates[i] == candidates[i+1] {
			i++
		}
		arr = append(arr, candidates[i])
		dfs(candidates, target-candidates[i], arr, origin+1)
		arr = arr[:len(arr)-1]
	}
}

#
var res [][]int

func combinationSum2(candidates []int, target int) [][]int {
	res = make([][]int, 0)
	sort.Ints(candidates)
	dfs(candidates, target, []int{}, 0)
	return res
}

func dfs(candidates []int, target int, arr []int, index int) {
	if target == 0 {
		temp := make([]int, len(arr))
		copy(temp, arr)
		res = append(res, temp)
		return
	}
	for i := index; i < len(candidates); i++ {
		if i != index && candidates[i] == candidates[i-1] {
			continue
		}
		if target < 0 {
			return
		}
		arr = append(arr, candidates[i])
		dfs(candidates, target-candidates[i], arr, i+1)
		arr = arr[:len(arr)-1]
	}
}

43.字符串相乘(1)

  • 题目

给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,
它们的乘积也表示为字符串形式。
示例 1:输入: num1 = "2", num2 = "3"输出: "6"
示例 2:输入: num1 = "123", num2 = "456"输出: "56088"
说明:
    num1 和 num2 的长度小于110。
    num1 和 num2 只包含数字 0-9。
    num1 和 num2 均不以零开头,除非是数字 0 本身。
    不能使用任何标准库的大数类型(比如 BigInteger)或直接将输入转换为整数来处理。
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 模拟 O(n^2) O(n)
02 内置函数 O(n^2) O(n)
func multiply(num1 string, num2 string) string {
	if num1 == "0" || num2 == "0" {
		return "0"
	}
	arr := make([]int, len(num1)+len(num2))
	for i := len(num1) - 1; i >= 0; i-- {
		a := int(num1[i] - '0')
		for j := len(num2) - 1; j >= 0; j-- {
			b := int(num2[j] - '0')
			value := a*b + arr[i+j+1]
			arr[i+j+1] = value % 10
			arr[i+j] = value/10 + arr[i+j]
		}
	}
	res := ""
	for i := 0; i < len(arr); i++ {
		if i == 0 && arr[i] == 0 {
			continue
		}
		res = res + string(arr[i]+'0')
	}
	return res
}

# 2
func multiply(num1 string, num2 string) string {
	a, b := new(big.Int), new(big.Int)
	a.SetString(num1, 10)
	b.SetString(num2, 10)
	a.Mul(a, b)
	return a.String()
}

46.全排列(3)

  • 题目

给定一个 没有重复 数字的序列,返回其所有可能的全排列。
示例:输入: [1,2,3]输出:
[
  [1,2,3],
  [1,3,2],
  [2,1,3],
  [2,3,1],
  [3,1,2],
  [3,2,1]
]
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 回溯 O(n^n) O(n*n!)
02 递归 O(n!) O(n*n!)
03 回溯 O(n!) O(n*n!)
var res [][]int

func permute(nums []int) [][]int {
	res = make([][]int, 0)
	arr := make([]int, 0)
	visited := make(map[int]bool)
	dfs(nums, 0, arr, visited)
	return res
}

func dfs(nums []int, index int, arr []int, visited map[int]bool) {
	if index == len(nums) {
		temp := make([]int, len(arr))
		copy(temp, arr)
		res = append(res, temp)
		return
	}
	for i := 0; i < len(nums); i++ {
		if visited[i] == false {
			arr = append(arr, nums[i])
			visited[i] = true
			dfs(nums, index+1, arr, visited)
			arr = arr[:len(arr)-1]
			visited[i] = false
		}
	}
}

#
func permute(nums []int) [][]int {
	if len(nums) == 1 {
		return [][]int{nums}
	}
	res := make([][]int, 0)
	for i := 0; i < len(nums); i++ {
		tempArr := make([]int, len(nums)-1)
		copy(tempArr[0:], nums[:i])
		copy(tempArr[i:], nums[i+1:])
		arr := permute(tempArr)
		for _, v := range arr {
			res = append(res, append(v, nums[i]))
		}
	}
	return res
}

#
var res [][]int

func permute(nums []int) [][]int {
	res = make([][]int, 0)
	arr := make([]int, len(nums))
	dfs(nums, 0, arr)
	return res
}

func dfs(nums []int, index int, arr []int) {
	if index == len(nums) {
		temp := make([]int, len(arr))
		copy(temp, arr)
		res = append(res, temp)
		return
	}
	for i := index; i < len(nums); i++ {
		arr[index] = nums[i]
		nums[i], nums[index] = nums[index], nums[i]
		dfs(nums, index+1, arr)
		nums[i], nums[index] = nums[index], nums[i]
	}
}

47.全排列II(3)

  • 题目

给定一个可包含重复数字的序列,返回所有不重复的全排列。
示例:输入: [1,1,2] 输出:
[
  [1,1,2],
  [1,2,1],
  [2,1,1]
]
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 回溯 O(n!) O(n!)
02 回溯 O(n!) O(n!)
03 回溯 O(n!) O(n!)
var res [][]int

func permuteUnique(nums []int) [][]int {
	res = make([][]int, 0)
	sort.Ints(nums)
	dfs(nums, 0, make([]int, len(nums)), make([]int, 0))
	return res
}

func dfs(nums []int, index int, visited []int, arr []int) {
	if len(nums) == index {
		temp := make([]int, len(arr))
		copy(temp, arr)
		res = append(res, temp)
		return
	}
	for i := 0; i < len(nums); i++ {
		if visited[i] == 1 {
			continue
		}
		// visited[i-1] == 0 或者 visited[i-1] == 1都可以
		if i > 0 && nums[i] == nums[i-1] && visited[i-1] == 0 {
			// if i > 0 && nums[i] == nums[i-1] && visited[i-1] == 1 {
			continue
		}
		arr = append(arr, nums[i])
		visited[i] = 1
		dfs(nums, index+1, visited, arr)
		visited[i] = 0
		arr = arr[:len(arr)-1]
	}
}

# 2
var res [][]int

func permuteUnique(nums []int) [][]int {
	res = make([][]int, 0)
	sort.Ints(nums)
	dfs(nums, 0)
	return res
}

func dfs(nums []int, index int) {
	if index == len(nums) {
		temp := make([]int, len(nums))
		copy(temp, nums)
		res = append(res, temp)
		return
	}
	m := make(map[int]int)
	for i := index; i < len(nums); i++ {
		if _, ok := m[nums[i]]; ok {
			continue
		}
		m[nums[i]] = 1
		nums[i], nums[index] = nums[index], nums[i]
		dfs(nums, index+1)
		nums[i], nums[index] = nums[index], nums[i]
	}
}

# 3
var res [][]int

func permuteUnique(nums []int) [][]int {
	res = make([][]int, 0)
	sort.Ints(nums)
	dfs(nums, make([]int, 0))
	return res
}

func dfs(nums []int, arr []int) {
	if len(nums) == 0 {
		temp := make([]int, len(arr))
		copy(temp, arr)
		res = append(res, temp)
		return
	}
	for i := 0; i < len(nums); i++ {
		if i != 0 && nums[i] == nums[i-1] {
			continue
		}
		tempArr := make([]int, len(nums))
		copy(tempArr, nums)
		arr = append(arr, nums[i])
		dfs(append(tempArr[:i], tempArr[i+1:]...), arr)
		arr = arr[:len(arr)-1]
	}
}

48.旋转图像(3)

  • 题目

给定一个 n × n 的二维矩阵表示一个图像。
将图像顺时针旋转 90 度。
说明:你必须在原地旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要使用另一个矩阵来旋转图像。
示例 1:给定 matrix = 
[
  [1,2,3],
  [4,5,6],
  [7,8,9]
],
原地旋转输入矩阵,使其变为:
[
  [7,4,1],
  [8,5,2],
  [9,6,3]
]
示例 2:给定 matrix =
[
  [ 5, 1, 9,11],
  [ 2, 4, 8,10],
  [13, 3, 6, 7],
  [15,14,12,16]
], 
原地旋转输入矩阵,使其变为:
[
  [15,13, 2, 5],
  [14, 3, 4, 1],
  [12, 6, 8, 9],
  [16, 7,10,11]
]
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 遍历 O(n^2) O(1)
02 遍历 O(n^2) O(1)
03 数组辅助 O(n^2) O(n^2)
func rotate(matrix [][]int) {
	n := len(matrix)
	// 同行逆置
	// [[1 2 3] [4 5 6] [7 8 9]]
	// [[3 2 1] [6 5 4] [9 8 7]]
	for i := 0; i < n; i++ {
		for j := 0; j < n/2; j++ {
			matrix[i][j], matrix[i][n-1-j] = matrix[i][n-1-j], matrix[i][j]
		}
	}
	// 左下右上对角线对互换
	// [[3 2 1] [6 5 4] [9 8 7]]
	// [[7 4 1] [8 5 2] [9 6 3]]
	for i := 0; i < n-1; i++ {
		for j := 0; j < n-1-i; j++ {
			matrix[i][j], matrix[n-1-j][n-1-i] = matrix[n-1-j][n-1-i], matrix[i][j]
		}
	}
}

# 2
func rotate(matrix [][]int) {
	n := len(matrix)
	for start, end := 0, n-1; start < end; {
		for s, e := start, end; s < end; {
			matrix[start][s], matrix[e][start], matrix[end][e], matrix[s][end] =
				matrix[e][start], matrix[end][e], matrix[s][end], matrix[start][s]
			s++
			e--
		}
		start++
		end--
	}
}

# 3
func rotate(matrix [][]int) {
	n := len(matrix)
	arr := make([][]int, n)
	for i := 0; i < n; i++ {
		arr[i] = make([]int, n)
	}
	for i := 0; i < n; i++ {
		for j := 0; j < n; j++ {
			arr[j][n-1-i] = matrix[i][j]
		}
	}
	copy(matrix, arr)
}

49.字母异位词分组(2)

  • 题目

给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。
示例:输入: ["eat", "tea", "tan", "ate", "nat", "bat"]
输出:
[
  ["ate","eat","tea"],
  ["nat","tan"],
  ["bat"]
]
说明:
    所有输入均为小写字母。
    不考虑答案输出的顺序。
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 哈希辅助 O(n^2log(n)) O(n^2)
02 哈希辅助 O(n^2) O(n^2)
func groupAnagrams(strs []string) [][]string {
	m := make(map[string]int)
	res := make([][]string, 0)
	for i := 0; i < len(strs); i++ {
		arr := []byte(strs[i])
		sort.Slice(arr, func(i, j int) bool {
			return arr[i] < arr[j]
		})
		newStr := string(arr)
		if _, ok := m[newStr]; ok {
			res[m[newStr]] = append(res[m[newStr]], strs[i])
		} else {
			m[newStr] = len(res)
			res = append(res, []string{strs[i]})
		}
	}
	return res
}

#
func groupAnagrams(strs []string) [][]string {
	m := make(map[[26]int]int)
	res := make([][]string, 0)
	for i := 0; i < len(strs); i++ {
		arr := [26]int{}
		for j := 0; j < len(strs[i]); j++{
			arr[strs[i][j]-'a']++
		}
		if _, ok := m[arr]; ok {
			res[m[arr]] = append(res[m[arr]], strs[i])
		} else {
			m[arr] = len(res)
			res = append(res, []string{strs[i]})
		}
	}
	return res
}

50.Pow(x,n)(4)

  • 题目

实现 pow(x, n) ,即计算 x 的 n 次幂函数。
示例 1:输入: 2.00000, 10 输出: 1024.00000
示例 2:输入: 2.10000, 3 输出: 9.26100
示例 3:输入: 2.00000, -2 输出: 0.25000
解释: 2-2 = 1/22 = 1/4 = 0.25
说明:  -100.0 < x < 100.0
    n 是 32 位有符号整数,其数值范围是 [−231, 231 − 1] 。
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 递归 O(log(n)) O(1)
02 迭代 O(log(n)) O(1)
03 计算 O(log(n)) O(1)
04 递归 O(log(n)) O(log(n))
func myPow(x float64, n int) float64 {
	if n == 0 {
		return 1
	}
	if n < 0 {
		return 1 / myPow(x, -n)
	}
	if n%2 == 1 {
		return x * myPow(x, n-1)
	}
	return myPow(x*x, n/2)
}

#
func myPow(x float64, n int) float64 {
	if n < 0 {
		x = 1 / x
		n = -n
	}
	res := float64(1)
	for n > 0 {
		if n%2 == 1 {
			res = res * x
		}
		x = x * x
		n = n / 2
	}
	return res
}

#
func myPow(x float64, n int) float64 {
	return math.Pow(x, float64(n))
}

#
func myPow(x float64, n int) float64 {
	if n == 0 {
		return 1
	}
	if n == 1 {
		return x
	}
	res := 1.0
	if n > 0 {
		res = myPow(x, n/2)
		return res * res * myPow(x, n%2)
	} else {
		res = myPow(x, -n/2)
		res = res * res * myPow(x, -n%2)
		return 1 / res
	}
}

54.螺旋矩阵(2)

  • 题目

给定一个包含 m x n 个元素的矩阵(m 行, n 列),请按照顺时针螺旋顺序,返回矩阵中的所有元素。
示例 1:输入:
[
 [ 1, 2, 3 ],
 [ 4, 5, 6 ],
 [ 7, 8, 9 ]
]
输出: [1,2,3,6,9,8,7,4,5]
示例 2:输入:
[
  [1, 2, 3, 4],
  [5, 6, 7, 8],
  [9,10,11,12]
]
输出: [1,2,3,4,8,12,11,10,9,5,6,7]
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 遍历 O(n^2) O(n^2)
02 遍历 O(n^2) O(n^2)
var res []int

func spiralOrder(matrix [][]int) []int {
	res = make([]int, 0)
	rows := len(matrix)
	if rows == 0 {
		return res
	}
	cols := len(matrix[0])
	if cols == 0 {
		return res
	}
	start := 0
	for cols > start*2 && rows > start*2 {
		printCircle(matrix, cols, rows, start)
		start++
	}
	return res
}

func printCircle(matrix [][]int, cols, rows, start int) {
	x := cols - 1 - start
	y := rows - 1 - start
	// 左到右
	for i := start; i <= x; i++ {
		res = append(res, matrix[start][i])
	}
	// 上到下
	if start < y {
		for i := start + 1; i <= y; i++ {
			res = append(res, matrix[i][x])
		}
	}
	// 右到左
	if start < x && start < y {
		for i := x - 1; i >= start; i-- {
			res = append(res, matrix[y][i])
		}
	}
	// 下到上
	if start < x && start < y-1 {
		for i := y - 1; i >= start+1; i-- {
			res = append(res, matrix[i][start])
		}
	}
}

#
func spiralOrder(matrix [][]int) []int {
	res := make([]int, 0)
	rows := len(matrix)
	if rows == 0 {
		return res
	}
	cols := len(matrix[0])
	if cols == 0 {
		return res
	}
	x1, x2, y1, y2 := 0, rows-1, 0, cols-1
	direct := 0
	for x1 <= x2 && y1 <= y2 {
		direct = (direct + 4) % 4
		if direct == 0 {
			for i := y1; i <= y2; i++ {
				res = append(res, matrix[x1][i])
			}
			x1++
		} else if direct == 1 {
			for i := x1; i <= x2; i++ {
				res = append(res, matrix[i][y2])
			}
			y2--
		} else if direct == 2 {
			for i := y2; i >= y1; i-- {
				res = append(res, matrix[x2][i])
			}
			x2--
		} else if direct == 3 {
			for i := x2; i >= x1; i-- {
				res = append(res, matrix[i][y1])
			}
			y1++
		}
		direct++
	}
	return res
}

55.跳跃游戏(4)

  • 题目

给定一个非负整数数组,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否能够到达最后一个位置。
示例 1:输入: [2,3,1,1,4] 输出: true
解释: 我们可以先跳 1 步,从位置 0 到达 位置 1, 然后再从位置 1 跳 3 步到达最后一个位置。
示例 2:输入: [3,2,1,0,4] 输出: false
解释: 无论怎样,你总会到达索引为 3 的位置。但该位置的最大跳跃长度是 0 , 
所以你永远不可能到达最后一个位置。
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 遍历-贪心 O(n) O(1)
02 动态规划 O(n^2) O(n)
03 遍历-贪心 O(n) O(1)
04 遍历 O(n) O(1)
func canJump(nums []int) bool {
	j := len(nums) - 1
	for i := len(nums) - 2; i >= 0; i-- {
		if nums[i]+i >= j {
			j = i
		}
	}
	return j <= 0
}

#
func canJump(nums []int) bool {
	if len(nums) <= 1 {
		return true
	}
	dp := make([]bool, len(nums))
	dp[0] = true
	for i := 1; i < len(nums); i++ {
		flag := false
		for j := 0; j < i; j++ {
			if dp[j] && nums[j]+j >= i {
				flag = true
				break
			}
		}
		dp[i] = flag
	}
	return dp[len(nums)-1]
}

#
func canJump(nums []int) bool {
	max := 0
	for i := 0; i < len(nums); i++ {
		if i <= max {
			if i+nums[i] > max {
				max = i + nums[i]
			}
			if max >= len(nums)-1 {
				return true
			}
		}
	}
	return false
}

#
func canJump(nums []int) bool {
	zero := -1
	for i := len(nums) - 2; i >= 0; i-- {
		if zero > 0 {
			if i+nums[i] > zero {
				zero = -1
			}
			continue
		}
		if nums[i] == 0 {
			zero = i
			continue
		}
	}
	return zero < 0
}

56.合并区间(2)

  • 题目

给出一个区间的集合,请合并所有重叠的区间。
示例 1:输入: [[1,3],[2,6],[8,10],[15,18]] 输出: [[1,6],[8,10],[15,18]]
解释: 区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].
示例 2:输入: [[1,4],[4,5]] 输出: [[1,5]]
解释: 区间 [1,4] 和 [4,5] 可被视为重叠区间。
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 排序遍历 O(nlog(n)) O(n)
02 排序-双指针 O(nlog(n)) O(n)
func merge(intervals [][]int) [][]int {
	res := make([][]int, 0)
	if len(intervals) == 0 {
		return nil
	}
	sort.Slice(intervals, func(i, j int) bool {
		return intervals[i][0] < intervals[j][0]
	})
	res = append(res, intervals[0])
	for i := 1; i < len(intervals); i++ {
		arr := res[len(res)-1]
		if intervals[i][0] > arr[1] {
			res = append(res, intervals[i])
		} else if intervals[i][1] > arr[1] {
			res[len(res)-1][1] = intervals[i][1]
		}
	}
	return res
}

#
func merge(intervals [][]int) [][]int {
	res := make([][]int, 0)
	if len(intervals) == 0 {
		return nil
	}
	sort.Slice(intervals, func(i, j int) bool {
		return intervals[i][0] < intervals[j][0]
	})
	for i := 0; i < len(intervals); {
		end := intervals[i][1]
		j := i + 1
		for j < len(intervals) && intervals[j][0] <= end {
			if intervals[j][1] > end {
				end = intervals[j][1]
			}
			j++
		}
		res = append(res, []int{intervals[i][0], end})
		i = j
	}
	return res
}

59.螺旋矩阵II(2)

  • 题目

给定一个正整数 n,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。
示例:输入: 3 输出:
[
 [ 1, 2, 3 ],
 [ 8, 9, 4 ],
 [ 7, 6, 5 ]
]
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 遍历 O(n^2) O(n^2)
02 遍历模拟 O(n^2) O(n^2)
func generateMatrix(n int) [][]int {
	res := make([][]int, n)
	for i := 0; i < n; i++ {
		res[i] = make([]int, n)
	}
	count := 1
	level := 1
	for count <= n*n {
		top, bottom, left, right := level-1, n-level, level-1, n-level
		// 左到右
		for i := left; i <= right && left <= right; i++ {
			res[top][i] = count
			count++
		}
		// 上到下
		for i := top + 1; i <= bottom && top <= bottom; i++ {
			res[i][right] = count
			count++
		}
		// 右到左
		for i := right - 1; i >= left && left <= right; i-- {
			res[bottom][i] = count
			count++
		}
		// 下到上
		for i := bottom - 1; i >= top+1 && top <= bottom; i-- {
			res[i][left] = count
			count++
		}
		level++
	}
	return res
}

#
func generateMatrix(n int) [][]int {
	res := make([][]int, n)
	for i := 0; i < n; i++ {
		res[i] = make([]int, n)
	}
	count := 1
	top, bottom, left, right := 0, n-1, 0, n-1
	for count <= n*n {
		for i := left; i <= right; i++ {
			res[top][i] = count
			count++
		}
		top++
		for i := top; i <= bottom; i++ {
			res[i][right] = count
			count++
		}
		right--
		for i := right; i >= left; i-- {
			res[bottom][i] = count
			count++
		}
		bottom--
		for i := bottom; i >= top; i-- {
			res[i][left] = count
			count++
		}
		left++
	}
	return res
}

60.第k个排列(1)

  • 题目

给出集合 [1,2,3,…,n],其所有元素共有 n! 种排列。
按大小顺序列出所有排列情况,并一一标记,当 n = 3 时, 所有排列如下:
    "123"
    "132"
    "213"
    "231"
    "312"
    "321"
给定 n 和 k,返回第 k 个排列。
说明:
    给定 n 的范围是 [1, 9]。
    给定 k 的范围是[1,  n!]。
示例 1:输入: n = 3, k = 3 输出: "213"
示例 2:输入: n = 4, k = 9 输出: "2314"
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 遍历计算 O(n) O(n)
func getPermutation(n int, k int) string {
	res := ""
	arr := []string{"1", "2", "3", "4", "5", "6", "7", "8", "9"}
	times := make([]int, 0)
	times = append(times, 1)
	value := 1
	for i := 1; i <= 9; i++ {
		times = append(times, value*i)
		value = value * i
	}
	k--
	for n > 0 {
		i := k / times[n-1]
		k = k % times[n-1]
		n--
		res = res + arr[i]
		arr = append(arr[:i], arr[i+1:]...)
	}
	return res
}

61.旋转链表(2)

  • 题目

给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数。
示例 1:
输入: 1->2->3->4->5->NULL, k = 2
输出: 4->5->1->2->3->NULL
解释:
向右旋转 1 步: 5->1->2->3->4->NULL
向右旋转 2 步: 4->5->1->2->3->NULL
示例 2:
输入: 0->1->2->NULL, k = 4
输出: 2->0->1->NULL
解释:
向右旋转 1 步: 2->0->1->NULL
向右旋转 2 步: 1->2->0->NULL
向右旋转 3 步: 0->1->2->NULL
向右旋转 4 步: 2->0->1->NULL
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 统计遍历 O(n) O(1)
02 数组辅助 O(n) O(n)
func rotateRight(head *ListNode, k int) *ListNode {
	if head == nil || k == 0 {
		return head
	}
	temp := head
	count := 1
	for temp.Next != nil {
		temp = temp.Next
		count++
	}
	temp.Next = head
	k = k % count
	for i := 0; i < count-k; i++ {
		temp = temp.Next
	}
	head, temp.Next = temp.Next, nil
	return head
}

#
func rotateRight(head *ListNode, k int) *ListNode {
	if head == nil || k == 0 {
		return head
	}
	temp := head
	count := 0
	arr := make([]*ListNode, 0)
	for temp != nil {
		arr = append(arr, temp)
		temp = temp.Next
		count++
	}
	k = k % count
	if k == 0 {
		return head
	}
	arr[count-1].Next = head
	temp = arr[count-1-k]
	head, temp.Next = temp.Next, nil
	return head
}

62.不同路径(4)

  • 题目

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。
问总共有多少条不同的路径?
例如,上图是一个7 x 3 的网格。有多少可能的路径?
示例 1:输入: m = 3, n = 2 输出: 3
解释:
从左上角开始,总共有 3 条路径可以到达右下角。
1. 向右 -> 向右 -> 向下
2. 向右 -> 向下 -> 向右
3. 向下 -> 向右 -> 向右
示例 2:输入: m = 7, n = 3 输出: 28
提示:
    1 <= m, n <= 100
    题目数据保证答案小于等于 2 * 10 ^ 9
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 动态规划 O(n^2) O(n^2)
02 动态规划 O(n^2) O(n)
03 数学 O(n) O(1)
04 递归 O(n^2) O(n^2)
// dp[i][j] = dp[i-1][j] + dp[i][j-1]
func uniquePaths(m int, n int) int {
	if m <= 0 || n <= 0 {
		return 0
	}
	dp := make([][]int, n)
	for i := 0; i < n; i++ {
		dp[i] = make([]int, m)
		dp[i][0] = 1
	}
	for i := 0; i < m; i++ {
		dp[0][i] = 1
	}
	for i := 1; i < n; i++ {
		for j := 1; j < m; j++ {
			dp[i][j] = dp[i-1][j] + dp[i][j-1]
		}
	}
	return dp[n-1][m-1]
}

#
// dp[i]= dp[i-1] + dp[i]
func uniquePaths(m int, n int) int {
	if m <= 0 || n <= 0 {
		return 0
	}
	dp := make([]int, n)
	for i := 0; i < n; i++ {
		dp[i] = 1
	}
	for i := 1; i < m; i++ {
		for j := 1; j < n; j++ {
			dp[j] = dp[j] + dp[j-1]
		}
	}
	return dp[n-1]
}

# 3
func uniquePaths(m int, n int) int {
	if m == 1 || n == 1 {
		return 1
	}
	if m > n {
		m, n = n, m
	}
	a := 1
	for i := 1; i <= m-1; i++ {
		a = a * i
	}
	b := 1
	for i := n; i <= m+n-2; i++ {
		b = b * i
	}
	return b / a
}

# 4
var arr [][]int

func uniquePaths(m int, n int) int {
	arr = make([][]int, n+1)
	for i := 0; i <= n; i++ {
		arr[i] = make([]int, m+1)
	}
	return dfs(m, n)
}

func dfs(m, n int) int {
	if m <= 0 || n <= 0 {
		return 0
	}
	if m == 1 || n == 1 {
		return 1
	}
	if arr[n][m] > 0 {
		return arr[n][m]
	}
	arr[n][m] = dfs(m, n-1) + dfs(m-1, n)
	return arr[n][m]
}

63.不同路径II(3)

  • 题目

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。
现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?
网格中的障碍物和空位置分别用 1 和 0 来表示。
说明:m 和 n 的值均不超过 100。
示例 1:
输入:
[
  [0,0,0],
  [0,1,0],
  [0,0,0]
]
输出: 2
解释:
3x3 网格的正中间有一个障碍物。
从左上角到右下角一共有 2 条不同的路径:
1. 向右 -> 向右 -> 向下 -> 向下
2. 向下 -> 向下 -> 向右 -> 向右
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 动态规划 O(n^2) O(n^2)
02 动态规划 O(n^2) O(n)
03 动态规划 O(n^2) O(1)
func uniquePathsWithObstacles(obstacleGrid [][]int) int {
	n := len(obstacleGrid)
	if n < 1 {
		return 0
	}
	m := len(obstacleGrid[0])
	if m < 1 {
		return 0
	}
	if obstacleGrid[0][0] == 1 {
		return 0
	}
	dp := make([][]int, n)
	for i := 0; i < n; i++ {
		dp[i] = make([]int, m)
		for j := 0; j < m; j++ {
			if i == 0 && j == 0 {
				dp[i][j] = 1
			} else if i == 0 && j != 0 {
				if obstacleGrid[i][j] == 0 {
					dp[i][j] = dp[i][j-1]
				}
			} else if i != 0 && j == 0 {
				if obstacleGrid[i][j] == 0 {
					dp[i][j] = dp[i-1][j]
				}
			} else {
				if obstacleGrid[i][j] == 0 {
					dp[i][j] = dp[i-1][j] + dp[i][j-1]
				}
			}
		}
	}
	return dp[n-1][m-1]
}

# 2
// dp[j] = dp[j] + dp[j-1]
func uniquePathsWithObstacles(obstacleGrid [][]int) int {
	n := len(obstacleGrid)
	if n < 1 {
		return 0
	}
	m := len(obstacleGrid[0])
	if m < 1 {
		return 0
	}
	if obstacleGrid[0][0] == 1 {
		return 0
	}
	dp := make([]int, m)
	dp[0] = 1
	for i := 0; i < n; i++ {
		for j := 0; j < m; j++ {
			if obstacleGrid[i][j] == 1 {
				dp[j] = 0
				continue
			}
			if j >= 1 && obstacleGrid[i][j-1] == 0 {
				dp[j] = dp[j] + dp[j-1]
			}
		}
	}
	return dp[m-1]
}

# 3
func uniquePathsWithObstacles(obstacleGrid [][]int) int {
	n := len(obstacleGrid)
	if n < 1 {
		return 0
	}
	m := len(obstacleGrid[0])
	if m < 1 {
		return 0
	}
	if obstacleGrid[0][0] == 1 {
		return 0
	}
	for i := 0; i < n; i++ {
		for j := 0; j < m; j++ {
			if obstacleGrid[i][j] == 1 {
				obstacleGrid[i][j] = 0
				continue
			}
			if i == 0 {
				if j == 0 {
					obstacleGrid[i][j] = 1
				} else {
					obstacleGrid[i][j] += obstacleGrid[i][j-1]
				}
			} else {
				if j == 0 {
					obstacleGrid[i][j] += obstacleGrid[i-1][j]
				} else {
					obstacleGrid[i][j] += obstacleGrid[i][j-1] + obstacleGrid[i-1][j]
				}
			}
		}
	}
	return obstacleGrid[n-1][m-1]
}

64.最小路径和(4)

  • 题目

给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
说明:每次只能向下或者向右移动一步。
示例:
输入:
[
  [1,3,1],
  [1,5,1],
  [4,2,1]
]
输出: 7解释: 因为路径 1→3→1→1→1 的总和最小。
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 动态规划 O(n^2) O(n^2)
02 动态规划 O(n^2) O(1)
03 动态规划 O(n^2) O(n)
04 递归 O(n^2) O(n^2)
func minPathSum(grid [][]int) int {
	n := len(grid)
	if n == 0 {
		return 0
	}
	m := len(grid[0])
	dp := make([][]int, n)
	for i := 0; i < n; i++ {
		dp[i] = make([]int, m)
	}
	dp[0][0] = grid[0][0]
	for i := 0; i < n; i++ {
		for j := 0; j < m; j++ {
			if i == 0 && j != 0 {
				dp[i][j] = dp[i][j-1] + grid[i][j]
			} else if i != 0 && j == 0 {
				dp[i][j] = dp[i-1][j] + grid[i][j]
			} else if i != 0 && j != 0 {
				dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + grid[i][j]
			}
		}
	}
	return dp[n-1][m-1]
}

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

#
func minPathSum(grid [][]int) int {
	n := len(grid)
	if n == 0 {
		return 0
	}
	m := len(grid[0])
	for i := 0; i < n; i++ {
		for j := 0; j < m; j++ {
			if i == 0 && j != 0 {
				grid[i][j] = grid[i][j-1] + grid[i][j]
			} else if i != 0 && j == 0 {
				grid[i][j] = grid[i-1][j] + grid[i][j]
			} else if i != 0 && j != 0 {
				grid[i][j] = min(grid[i-1][j], grid[i][j-1]) + grid[i][j]
			}
		}
	}
	return grid[n-1][m-1]
}

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

# 3
func minPathSum(grid [][]int) int {
	n := len(grid)
	if n == 0 {
		return 0
	}
	m := len(grid[0])
	dp := make([]int, m)
	dp[0] = grid[0][0]

	for i := 1; i < m; i++ {
		dp[i] = dp[i-1] + grid[0][i]
	}
	for i := 1; i < n; i++ {
		dp[0] = dp[0] + grid[i][0]
		for j := 1; j < m; j++ {
			dp[j] = min(dp[j-1], dp[j]) + grid[i][j]
		}
	}
	return dp[m-1]
}

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

# 4
var arr [][]int

func minPathSum(grid [][]int) int {
	n := len(grid)
	if n == 0 {
		return 0
	}
	m := len(grid[0])
	arr = make([][]int, n)
	for i := 0; i < n; i++ {
		arr[i] = make([]int, m)
	}
	return dfs(grid, n-1, m-1)
}

func dfs(grid [][]int, n, m int) int {
	if m == 0 && n == 0 {
		arr[0][0] = grid[0][0]
		return grid[0][0]
	}
	if n == 0 {
		return grid[0][m] + dfs(grid, 0, m-1)
	}
	if m == 0 {
		return grid[n][0] + dfs(grid, n-1, 0)
	}
	if arr[n][m] > 0 {
		return arr[n][m]
	}
	arr[n][m] = min(dfs(grid, n-1, m), dfs(grid, n, m-1)) + grid[n][m]
	return arr[n][m]
}

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

71.简化路径(2)

  • 题目

以 Unix 风格给出一个文件的绝对路径,你需要简化它。或者换句话说,将其转换为规范路径。
在 Unix 风格的文件系统中,一个点(.)表示当前目录本身;
此外,两个点 (..) 表示将目录切换到上一级(指向父目录);两者都可以是复杂相对路径的组成部分。
更多信息请参阅:Linux / Unix中的绝对路径 vs 相对路径
请注意,返回的规范路径必须始终以斜杠 / 开头,并且两个目录名之间必须只有一个斜杠 /。
最后一个目录名(如果存在)不能以 / 结尾。此外,规范路径必须是表示绝对路径的最短字符串。
示例 1:输入:"/home/" 输出:"/home"
解释:注意,最后一个目录名后面没有斜杠。
示例 2:输入:"/../" 输出:"/"
解释:从根目录向上一级是不可行的,因为根是你可以到达的最高级。
示例 3:输入:"/home//foo/" 输出:"/home/foo"
解释:在规范路径中,多个连续斜杠需要用一个斜杠替换。
示例 4:输入:"/a/./b/../../c/" 输出:"/c"
示例 5:输入:"/a/../../b/../c//.//" 输出:"/c"
示例 6:输入:"/a//b////c/d//././/.." 输出:"/a/b/c"
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 栈辅助 O(n) O(n)
02 内置函数 O(n) O(n)
func simplifyPath(path string) string {
	stack := make([]string, 0)
	arr := strings.Split(path, "/")
	for i := 0; i < len(arr); i++ {
		if arr[i] == "." || arr[i] == "" {
			continue
		}
		if arr[i] == ".." {
			if len(stack) > 0 {
				stack = stack[:len(stack)-1]
			}
		} else {
			stack = append(stack, arr[i])
		}
	}
	return "/" + strings.Join(stack, "/")
}

#
func simplifyPath(path string) string {
	return filepath.Clean(path)
}

73.矩阵置零(4)

  • 题目

给定一个 m x n 的矩阵,如果一个元素为 0,则将其所在行和列的所有元素都设为 0。请使用原地算法。
示例 1:
输入: 
[
  [1,1,1],
  [1,0,1],
  [1,1,1]
]
输出: 
[
  [1,0,1],
  [0,0,0],
  [1,0,1]
]
示例 2:
输入: 
[
  [0,1,2,0],
  [3,4,5,2],
  [1,3,1,5]
]
输出: 
[
  [0,0,0,0],
  [0,4,5,0],
  [0,3,1,0]
]
进阶:
    一个直接的解决方案是使用  O(mn) 的额外空间,但这并不是一个好的解决方案。
    一个简单的改进方案是使用 O(m + n) 的额外空间,但这仍然不是最好的解决方案。
    你能想出一个常数空间的解决方案吗?
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 哈希辅助 O(n^2) O(n)
02 暴力法 O(n^4) O(1)
03 遍历 O(n^2) O(1)
04 遍历 O(n^2) O(1)
func setZeroes(matrix [][]int) {
	x := make(map[int]int)
	y := make(map[int]int)
	for i := 0; i < len(matrix); i++ {
		for j := 0; j < len(matrix[i]); j++ {
			if matrix[i][j] == 0 {
				x[i] = 1
				y[j] = 1
			}
		}
	}
	for i := 0; i < len(matrix); i++ {
		for j := 0; j < len(matrix[i]); j++ {
			if x[i] == 1 || y[j] == 1 {
				matrix[i][j] = 0
			}
		}
	}
}

#
func setZeroes(matrix [][]int) {
	m := make(map[[2]int]bool)
	for i := 0; i < len(matrix); i++ {
		for j := 0; j < len(matrix[i]); j++ {
			if matrix[i][j] == math.MinInt32 {
				m[[2]int{i, j}] = true
			}
		}
	}
	for i := 0; i < len(matrix); i++ {
		for j := 0; j < len(matrix[i]); j++ {
			if matrix[i][j] == 0 {
				for k := 0; k < len(matrix); k++ {
					for l := 0; l < len(matrix[k]); l++ {
						if (k == i || l == j) && matrix[k][l] != 0 {
							delete(m, [2]int{k, l})
							matrix[k][l] = math.MinInt32
						}
					}
				}
			}
		}
	}
	for i := 0; i < len(matrix); i++ {
		for j := 0; j < len(matrix[i]); j++ {
			if matrix[i][j] == math.MinInt32 && m[[2]int{i, j}] == false {
				matrix[i][j] = 0
			}
		}
	}
}

# 3
func setZeroes(matrix [][]int) {
	flag := false
	for i := 0; i < len(matrix); i++ {
		if matrix[i][0] == 0 {
			flag = true
		}
		for j := 1; j < len(matrix[i]); j++ {
			if matrix[i][j] == 0 {
				matrix[i][0] = 0
				matrix[0][j] = 0
			}
		}
	}
	for i := 1; i < len(matrix); i++ {
		for j := 1; j < len(matrix[i]); j++ {
			if matrix[i][0] == 0 || matrix[0][j] == 0 {
				matrix[i][j] = 0
			}
		}
	}
	// 第一行处理
	if matrix[0][0] == 0 {
		for j := 0; j < len(matrix[0]); j++ {
			matrix[0][j] = 0
		}
	}
	// 第一列处理
	if flag == true {
		for i := 0; i < len(matrix); i++ {
			matrix[i][0] = 0
		}
	}
}

# 4
func setZeroes(matrix [][]int) {
	flag := false
	for i := 0; i < len(matrix); i++ {
		if matrix[i][0] == 0 {
			flag = true
		}
		for j := 1; j < len(matrix[i]); j++ {
			if matrix[i][j] == 0 {
				matrix[i][0] = 0
				matrix[0][j] = 0
			}
		}
	}
	for i := len(matrix) - 1; i >= 0; i-- {
		for j := len(matrix[i]) - 1; j >= 1; j-- {
			if matrix[i][0] == 0 || matrix[0][j] == 0 {
				matrix[i][j] = 0
			}
		}
	}
	// 第一列处理
	if flag == true {
		for i := 0; i < len(matrix); i++ {
			matrix[i][0] = 0
		}
	}
}

74.搜索二维矩阵(6)

  • 题目

编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值。该矩阵具有如下特性:
    每行中的整数从左到右按升序排列。
    每行的第一个整数大于前一行的最后一个整数。
示例 1:输入:
matrix = [
  [1,   3,  5,  7],
  [10, 11, 16, 20],
  [23, 30, 34, 50]
]
target = 3
输出: true
示例 2:输入:
matrix = [
  [1,   3,  5,  7],
  [10, 11, 16, 20],
  [23, 30, 34, 50]
]
target = 13
输出: false
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 暴力法 O(n^2) O(1)
02 暴力法-优化 O(n^2) O(1)
03 二分查找 O(nlog(n)) O(1)
04 左下角查找 O(n) O(1)
05 右上角查找 O(n) O(1)
06 内置函数 O(n^2) O(1)
func searchMatrix(matrix [][]int, target int) bool {
	if len(matrix) == 0 {
		return false
	}
	if len(matrix[0]) == 0 {
		return false
	}
	for i := 0; i < len(matrix); i++ {
		for j := 0; j < len(matrix[i]); j++ {
			if matrix[i][j] == target {
				return true
			}
		}
	}
	return false
}

# 2
func searchMatrix(matrix [][]int, target int) bool {
	if len(matrix) == 0 {
		return false
	}
	if len(matrix[0]) == 0 {
		return false
	}
	for i := 0; i < len(matrix); i++ {
		if matrix[i][0] <= target && matrix[i][len(matrix[i])-1] >= target {
			for j := 0; j < len(matrix[i]); j++ {
				if matrix[i][j] == target {
					return true
				}
			}
		}
	}
	return false
}

# 3
func searchMatrix(matrix [][]int, target int) bool {
	if len(matrix) == 0 {
		return false
	}
	if len(matrix[0]) == 0 {
		return false
	}
	for i := 0; i < len(matrix); i++ {
		if matrix[i][0] <= target && matrix[i][len(matrix[i])-1] >= target {
			res := binarySearch(matrix[i], target)
			if res == true {
				return true
			}
		}
	}
	return false
}

func binarySearch(arr []int, target int) bool {
	left := 0
	right := len(arr) - 1
	for left <= right {
		mid := left + (right-left)/2
		if arr[mid] == target {
			return true
		} else if arr[mid] > target {
			right = mid - 1
		} else {
			left = mid + 1
		}
	}
	return false
}

# 4
func searchMatrix(matrix [][]int, target int) bool {
	if len(matrix) == 0 {
		return false
	}
	if len(matrix[0]) == 0 {
		return false
	}
	i := len(matrix) - 1
	j := 0
	for i >= 0 && j < len(matrix[0]) {
		if matrix[i][j] == target {
			return true
		} else if matrix[i][j] > target {
			i--
		} else {
			j++
		}
	}
	return false
}

# 5
func searchMatrix(matrix [][]int, target int) bool {
	if len(matrix) == 0 {
		return false
	}
	if len(matrix[0]) == 0 {
		return false
	}
	i := 0
	j := len(matrix[0]) - 1
	for j >= 0 && i < len(matrix) {
		if matrix[i][j] == target {
			return true
		} else if matrix[i][j] > target {
			j--
		} else {
			i++
		}
	}
	return false
}

# 6
func searchMatrix(matrix [][]int, target int) bool {
	if len(matrix) == 0 {
		return false
	}
	if len(matrix[0]) == 0 {
		return false
	}
	for i := 0; i < len(matrix); i++ {
		index := sort.SearchInts(matrix[i], target)
		if index < len(matrix[i]) && target == matrix[i][index] {
			return true
		}
	}
	return false
}

75.颜色分类(3)

  • 题目

给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,
使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。
注意:
不能使用代码库中的排序函数来解决这道题。
示例:输入: [2,0,2,1,1,0] 输出: [0,0,1,1,2,2]
进阶:
    一个直观的解决方案是使用计数排序的两趟扫描算法。
    首先,迭代计算出0、1 和 2 元素的个数,然后按照0、1、2的排序,重写当前数组。
    你能想出一个仅使用常数空间的一趟扫描算法吗?
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 排序 O(nlog(n)) O(1)
02 双指针 O(n) O(1)
03 数组辅助 O(n) O(1)
func sortColors(nums []int) {
	sort.Ints(nums)
}

# 2
func sortColors(nums []int) {
	left := 0
	right := len(nums) - 1
	for i := 0; i <= right; i++ {
		if nums[i] == 0 {
			nums[left], nums[i] = nums[i], nums[left]
			left++
		} else if nums[i] == 2 {
			nums[right], nums[i] = nums[i], nums[right]
			right--
			i--
		}
	}
}

# 3
func sortColors(nums []int) {
	arr := make([]int, 3)
	for i := 0; i < len(nums); i++ {
		arr[nums[i]]++
	}
	count := 0
	for i := 0; i < len(arr); i++ {
		for j := 0; j < arr[i]; j++ {
			nums[count] = i
			count++
		}
	}
}

77.组合(5)

  • 题目

给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合。
示例:输入: n = 4, k = 2 输出:
[
  [2,4],
  [3,4],
  [2,3],
  [1,2],
  [1,3],
  [1,4],
]
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 回溯-递归 O(kC(n,k)) O(C(n,k))
02 回溯 O(kC(n,k)) O(C(n,k))
03 回溯 O(kC(n,k)) O(C(n,k))
04 迭代 O(kC(n,k)) O(C(n,k))
05 回溯 O(kC(n,k)) O(C(n,k))
var res [][]int

func combine(n int, k int) [][]int {
	res = make([][]int, 0)
	nums := make([]int, 0)
	for i := 1; i <= n; i++ {
		nums = append(nums, i)
	}
	dfs(nums, 0, k)
	return res
}

func dfs(nums []int, index, k int) {
	if index == k {
		temp := make([]int, k)
		copy(temp, nums[:k])
		res = append(res, temp)
		return
	}
	for i := index; i < len(nums); i++ {
		if index == 0 || nums[i] > nums[index-1] {
			nums[i], nums[index] = nums[index], nums[i]
			dfs(nums, index+1, k)
			nums[i], nums[index] = nums[index], nums[i]
		}
	}
}

# 2
var res [][]int

func combine(n int, k int) [][]int {
	res = make([][]int, 0)
	dfs(n, k, 1, make([]int, 0))
	return res
}

func dfs(n, k, index int, arr []int) {
	if len(arr) == k {
		temp := make([]int, k)
		copy(temp, arr)
		res = append(res, temp)
		return
	}
	for i := index; i <= n; i++ {
		arr = append(arr, i)
		dfs(n, k, i+1, arr)
		arr = arr[:len(arr)-1]
	}
}

# 3
var res [][]int

func combine(n int, k int) [][]int {
	res = make([][]int, 0)
	nums := make([]int, 0)
	for i := 1; i <= n; i++ {
		nums = append(nums, i)
	}
	dfs(nums, 0, k, make([]int, 0))
	return res
}

func dfs(nums []int, index, k int, arr []int) {
	if len(arr) == k {
		temp := make([]int, k)
		copy(temp, arr)
		res = append(res, temp)
		return
	}
	for i := index; i < len(nums); i++ {
		arr = append(arr, nums[i])
		dfs(nums, i+1, k, arr)
		arr = arr[:len(arr)-1]
	}
}

# 4
func combine(n int, k int) [][]int {
	res := make([][]int, 0)
	arr := make([]int, 0)
	for i := 1; i <= k; i++ {
		arr = append(arr, 0)
	}
	i := 0
	for i >= 0 {
		arr[i]++
		if arr[i] > n {
			i--
		} else if i == k-1 {
			temp := make([]int, k)
			copy(temp, arr)
			res = append(res, temp)
		} else {
			i++
			arr[i] = arr[i-1]
		}
	}
	return res
}

# 5
var res [][]int

func combine(n int, k int) [][]int {
	res = make([][]int, 0)
	dfs(n, k, 1, make([]int, 0))
	return res
}

func dfs(n, k, index int, arr []int) {
	if index > n+1 {
		return
	}
	if len(arr) == k {
		temp := make([]int, k)
		copy(temp, arr)
		res = append(res, temp)
		return
	}
	dfs(n, k, index+1, arr)
	arr = append(arr, index)
	dfs(n, k, index+1, arr)
}

78.子集(4)

  • 题目

给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
说明:解集不能包含重复的子集。
示例:输入: nums = [1,2,3] 输出:
[
  [3],
  [1],
  [2],
  [1,2,3],
  [1,3],
  [2,3],
  [1,2],
  []
]
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 回溯 O(n*2^n) O(n*2^n)
02 迭代 O(n*2^n) O(n*2^n)
03 位运算 O(n*2^n) O(n*2^n)
04 回溯 O(n*2^n) O(n*2^n)
var res [][]int

func subsets(nums []int) [][]int {
	res = make([][]int, 0)
	dfs(nums, make([]int, 0), 0)
	return res
}

func dfs(nums []int, arr []int, level int) {
	temp := make([]int, len(arr))
	copy(temp, arr)
	res = append(res, temp)
	for i := level; i < len(nums); i++ {
		dfs(nums, append(arr, nums[i]), i+1)
	}
}

# 2
func subsets(nums []int) [][]int {
	res := make([][]int, 0)
	res = append(res, []int{})
	for i := 0; i < len(nums); i++ {
		temp := make([][]int, len(res))
		for key, value := range res {
			value = append(value, nums[i])
			temp[key] = append(temp[key], value...)
		}
		for _, v := range temp {
			res = append(res, v)
		}
	}
	return res
}

# 3
func subsets(nums []int) [][]int {
	res := make([][]int, 0)
	n := len(nums)
	left := 1 << n
	right := 1 << (n + 1)
	for i := left; i < right; i++ {
		temp := make([]int, 0)
		for j := 0; j < n; j++ {
			if i&(1<<j) != 0 {
				temp = append(temp, nums[j])
			}
		}
		res = append(res, temp)
	}
	return res
}

# 4
var res [][]int

func subsets(nums []int) [][]int {
	res = make([][]int, 0)
	dfs(nums, make([]int, 0), 0)
	return res
}

func dfs(nums []int, arr []int, level int) {
	if level >= len(nums) {
		temp := make([]int, len(arr))
		copy(temp, arr)
		res = append(res, temp)
		return
	}
	dfs(nums, arr, level+1)
	dfs(nums, append(arr, nums[level]), level+1)
}

79.单词搜索(2)

  • 题目

给定一个二维网格和一个单词,找出该单词是否存在于网格中。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。
同一个单元格内的字母不允许被重复使用。
示例:board =
[
  ['A','B','C','E'],
  ['S','F','C','S'],
  ['A','D','E','E']
]
给定 word = "ABCCED", 返回 true
给定 word = "SEE", 返回 true
给定 word = "ABCB", 返回 false
提示:
    board 和 word 中只包含大写和小写英文字母。
    1 <= board.length <= 200
    1 <= board[i].length <= 200
    1 <= word.length <= 10^3
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 深度优先搜索+回溯 O(n^2) O(n)
02 深度优先搜索+回溯+数组辅助 O(n^2) O(n^2)
func exist(board [][]byte, word string) bool {
	for i := 0; i < len(board); i++ {
		for j := 0; j < len(board[0]); j++ {
			if dfs(board, i, j, word, 0) {
				return true
			}
		}
	}
	return false
}

func dfs(board [][]byte, i, j int, word string, level int) bool {
	if i < 0 || i >= len(board) || j < 0 || j >= len(board[0]) ||
		board[i][j] != word[level] {
		return false
	}
	if level == len(word)-1 {
		return true
	}
	temp := board[i][j]
	board[i][j] = ' '
	res := dfs(board, i+1, j, word, level+1) ||
		dfs(board, i-1, j, word, level+1) ||
		dfs(board, i, j+1, word, level+1) ||
		dfs(board, i, j-1, word, level+1)
	board[i][j] = temp
	return res
}

#
func exist(board [][]byte, word string) bool {
	visited := make([][]bool, len(board))
	for i := 0; i < len(board); i++ {
		visited[i] = make([]bool, len(board[0]))
	}
	for i := 0; i < len(board); i++ {
		for j := 0; j < len(board[0]); j++ {
			if dfs(board, i, j, word, 0, visited) {
				return true
			}
		}
	}
	return false
}

func dfs(board [][]byte, i, j int, word string, level int, visited [][]bool) bool {
	res := false
	if i >= 0 && i < len(board) && j >= 0 && j < len(board[0]) &&
		visited[i][j] == false && board[i][j] == word[level] {
		if level == len(word)-1 {
			return true
		}
		visited[i][j] = true
		level = level + 1
		res = dfs(board, i+1, j, word, level, visited) ||
			dfs(board, i-1, j, word, level, visited) ||
			dfs(board, i, j+1, word, level, visited) ||
			dfs(board, i, j-1, word, level, visited)
		if !res {
			visited[i][j] = false
			level = level - 1
		}
	}
	return res
}

80.删除排序数组中的重复项II(2)

  • 题目

给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素最多出现两次,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。
示例 1:给定 nums = [1,1,1,2,2,3],
函数应返回新长度 length = 5, 并且原数组的前五个元素被修改为 1, 1, 2, 2, 3 。
你不需要考虑数组中超出新长度后面的元素。
示例 2:给定 nums = [0,0,1,1,1,1,2,3,3],
函数应返回新长度 length = 7, 并且原数组的前五个元素被修改为 0, 0, 1, 1, 2, 3, 3 。
你不需要考虑数组中超出新长度后面的元素。
说明:为什么返回数值是整数,但输出的答案是数组呢?
请注意,输入数组是以“引用”方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。
你可以想象内部操作如下:
// nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝
int len = removeDuplicates(nums);
// 在函数里修改输入数组对于调用者是可见的。
// 根据你的函数返回的长度, 它会打印出数组中该长度范围内的所有元素。
for (int i = 0; i < len; i++) {
    print(nums[i]);
}
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 双指针 O(n) O(1)
02 双指针 O(n) O(1)
func removeDuplicates(nums []int) int {
	if len(nums) == 0 {
		return 0
	}
	if len(nums) == 1 {
		return 1
	}
	n := 2
	i := n
	for j := n; j < len(nums); j++ {
		if nums[i-n] != nums[j] {
			nums[i] = nums[j]
			i++
		}
	}
	return i
}

#
func removeDuplicates(nums []int) int {
	if len(nums) == 0 {
		return 0
	}
	prev := nums[0]
	count := 1
	j := 1
	for i := 1; i < len(nums); i++ {
		if nums[i] == prev {
			count = count + 1
		} else {
			count = 1
			prev = nums[i]
		}
		if count <= 2 {
			nums[j] = nums[i]
			j++
		}
	}
	return j
}

81.搜索旋转排序数组II(2)

  • 题目

假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [0,0,1,2,2,5,6] 可能变为 [2,5,6,0,0,1,2] )。
编写一个函数来判断给定的目标值是否存在于数组中。若存在返回 true,否则返回 false。
示例 1:输入: nums = [2,5,6,0,0,1,2], target = 0 输出: true
示例 2:输入: nums = [2,5,6,0,0,1,2], target = 3 输出: false
进阶:
    这是 搜索旋转排序数组 的延伸题目,本题中的 nums  可能包含重复元素。
    这会影响到程序的时间复杂度吗?会有怎样的影响,为什么?
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 遍历 O(n) O(1)
02 二分查找 O(log(n)) O(1)
func search(nums []int, target int) bool {
	for i := 0; i < len(nums); i++ {
		if target == nums[i] {
			return true
		}
	}
	return false
}

#
func search(nums []int, target int) bool {
	left, right := 0, len(nums)-1
	for left <= right {
		for left < right && nums[left] == nums[left+1] {
			left++
		}
		for left < right && nums[right] == nums[right-1] {
			right--
		}
		mid := left + (right-left)/2
		if nums[mid] == target {
			return true
		}
		if nums[left] <= nums[mid] {
			if nums[left] <= target && target < nums[mid] {
				right = mid - 1
			} else {
				left = mid + 1
			}
		} else {
			if nums[mid] < target && target <= nums[right] {
				left = mid + 1
			} else {
				right = mid - 1
			}
		}
	}
	return false
}

82.删除排序链表中的重复元素II(3)

  • 题目

给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中 没有重复出现 的数字。
示例 1:输入: 1->2->3->3->4->4->5 输出: 1->2->5
示例 2:输入: 1->1->1->2->3 输出: 2->3
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 遍历 O(n) O(1)
02 递归 O(n) O(n)
03 双指针 O(n) O(1)
func deleteDuplicates(head *ListNode) *ListNode {
	if head == nil || head.Next == nil {
		return head
	}
	temp := &ListNode{Next: head}
	cur := temp
	value := 0
	for cur.Next != nil && cur.Next.Next != nil {
		if cur.Next.Val == cur.Next.Next.Val {
			value = cur.Next.Val
			for cur.Next != nil && cur.Next.Val == value {
				cur.Next = cur.Next.Next
			}
		} else {
			cur = cur.Next
		}
	}
	return temp.Next
}

#
func deleteDuplicates(head *ListNode) *ListNode {
	if head == nil || head.Next == nil {
		return head
	}
	flag := false
	for head.Next != nil && head.Val == head.Next.Val{
		head = head.Next
		flag = true
	}
	head.Next = deleteDuplicates(head.Next)
	if flag{
		return head.Next
	}
	return head
}

#
func deleteDuplicates(head *ListNode) *ListNode {
	if head == nil || head.Next == nil {
		return head
	}
	flag := false
	for head.Next != nil && head.Val == head.Next.Val{
		head = head.Next
		flag = true
	}
	head.Next = deleteDuplicates(head.Next)
	if flag{
		return head.Next
	}
	return head
}

86.分隔链表(2)

  • 题目

给定一个链表和一个特定值 x,对链表进行分隔,使得所有小于 x 的节点都在大于或等于 x 的节点之前。
你应当保留两个分区中每个节点的初始相对位置。
示例:
输入: head = 1->4->3->2->5->2, x = 3
输出: 1->2->2->4->3->5
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 双指针 O(n) O(1)
02 数组辅助 O(n) O(n)
func partition(head *ListNode, x int) *ListNode {
	first := &ListNode{}
	second := &ListNode{}
	a := first
	b := second
	for head != nil {
		if head.Val < x {
			a.Next = head
			a = head
		} else {
			b.Next = head
			b = head
		}
		head = head.Next
	}
	b.Next = nil
	a.Next = second.Next
	return first.Next
}

#
func partition(head *ListNode, x int) *ListNode {
	a := make([]*ListNode, 0)
	b := make([]*ListNode, 0)

	for head != nil {
		if head.Val < x {
			a = append(a, head)
		} else {
			b = append(b, head)
		}
		head = head.Next
	}
	temp := &ListNode{}
	node := temp
	for i := 0; i < len(a); i++ {
		node.Next = a[i]
		node = node.Next
	}
	for i := 0; i < len(b); i++ {
		node.Next = b[i]
		node = node.Next
	}
	node.Next = nil
	return temp.Next
}

89.格雷编码(3)

  • 题目

格雷编码是一个二进制数字系统,在该系统中,两个连续的数值仅有一个位数的差异。
给定一个代表编码总位数的非负整数 n,打印其格雷编码序列。即使有多个不同答案,你也只需要返回其中一种。
格雷编码序列必须以 0 开头。
示例 1:输入: 2 输出: [0,1,3,2]
解释:
00 - 0
01 - 1
11 - 3
10 - 2
对于给定的 n,其格雷编码序列并不唯一。例如,[0,2,3,1] 也是一个有效的格雷编码序列。
00 - 0
10 - 2
11 - 3
01 - 1
示例 2:输入: 0 输出: [0]
解释: 我们定义格雷编码序列必须以 0 开头。
     给定编码总位数为 n 的格雷编码序列,其长度为 2n。当 n = 0 时,长度为 20 = 1。
     因此,当 n = 0 时,其格雷编码序列为 [0]。
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 遍历-推导 O(2^n) O(2^n)
02 公式 O(2^n) O(2^n)
03 遍历 O(2^n) O(2^n)
func grayCode(n int) []int {
	if n == 0 {
		return []int{0}
	}
	res := []int{0, 1}
	for i := 1; i < n; i++ {
		temp := make([]int, 0)
		value := 1 << i
		for j := len(res) - 1; j >= 0; j-- {
			// 10 1 11
			// 10 0 10
			// 100 10 110
			// 100 11 111
			// 100 1 101
			// 100 0 100
			// fmt.Printf("%b %b %b\n", value, res[j], res[j]^value)

			// temp = append(temp, res[j]|value)
			// temp = append(temp, res[j]^value)
			temp = append(temp, res[j]+value)
		}
		res = append(res, temp...)
	}
	return res
}

# 2
func grayCode(n int) []int {
	total := 1 << n
	res := make([]int, 0)
	for i := 0; i < total; i++ {
		res = append(res, i^(i>>1))
	}
	return res
}

# 3
func grayCode(n int) []int {
	if n == 0 {
		return []int{0}
	}
	res := []int{0, 1}
	for i := 1; i < n; i++ {
		value := 1 << i
		for j := len(res) - 1; j >= 0; j-- {
			res= append(res, res[j]+value)
		}
	}
	return res
}

90.子集II(2)

  • 题目

给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
说明:解集不能包含重复的子集。
示例:输入: [1,2,2] 输出:
[
  [2],
  [1],
  [1,2,2],
  [2,2],
  [1,2],
  []
]
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 回溯 O(n*2^n) O(n*2^n)
02 回溯 O(n*2^n) O(n*2^n)
var res [][]int

func subsetsWithDup(nums []int) [][]int {
	sort.Ints(nums)
	res = make([][]int, 0)
	dfs(nums, make([]int, 0), 0)
	return res
}

func dfs(nums []int, arr []int, level int) {
	temp := make([]int, len(arr))
	copy(temp, arr)
	res = append(res, temp)
	for i := level; i < len(nums); i++ {
		if i > level && nums[i] == nums[i-1] {
			continue
		}
		arr = append(arr, nums[i])
		dfs(nums, arr, i+1)
		arr = arr[:len(arr)-1]
	}
}

# 2
var res [][]int

func subsetsWithDup(nums []int) [][]int {
	sort.Ints(nums)
	res = make([][]int, 0)
	dfs(nums, make([]int, 0))
	return res
}

func dfs(nums []int, arr []int) {
	temp := make([]int, len(arr))
	copy(temp, arr)
	res = append(res, temp)
	for i := 0; i < len(nums); i++ {
		if i > 0 && nums[i] == nums[i-1] {
			continue
		}
		arr = append(arr, nums[i])
		dfs(nums[i+1:], arr)
		arr = arr[:len(arr)-1]
	}
}

91.解码方法(3)

  • 题目

一条包含字母 A-Z 的消息通过以下方式进行了编码:
'A' -> 1
'B' -> 2
...
'Z' -> 26
给定一个只包含数字的非空字符串,请计算解码方法的总数。
示例 1:输入: "12" 输出: 2
解释: 它可以解码为 "AB"(1 2)或者 "L"(12)。
示例 2:输入: "226" 输出: 3
解释: 它可以解码为 "BZ" (2 26), "VF" (22 6), 或者 "BBF" (2 2 6) 。
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 动态规划 O(n) O(1)
02 动态规划 O(n) O(n)
03 递归 O(n) O(n)
func numDecodings(s string) int {
	if s[0] == '0' {
		return 0
	}
	pre := 1
	cur := 1
	for i := 1; i < len(s); i++ {
		temp := cur
		if s[i] == '0' {
			if s[i-1] == '1' || s[i-1] == '2' {
				cur = pre
			} else {
				return 0
			}
		} else if s[i-1] == '1' || 
			(s[i-1] == '2' && s[i] >= '1' && s[i] <= '6') {
			cur = cur + pre
		}
		pre = temp
	}
	return cur
}

# 2
func numDecodings(s string) int {
	if s[0] == '0' {
		return 0
	}
	dp := make([]int, len(s)+1)
	dp[0] = 1
	for i := 0; i < len(s); i++{
		if s[i] == '0' {
			if i == 0 || s[i-1] == '1' || s[i-1] == '2' {
				return 0
			}
			dp[i+1] = dp[i-1]
		} else{
			if  i > 0 && (s[i-1] == '2' && s[i] >= '1' && s[i] <= '6') {
				dp[i+1] = dp[i-1]+dp[i]
			}else {
				dp[i+1] = dp[i]
			}
		}
	}
	return dp[len(s)]
}

# 3
var m map[string]int

func numDecodings(s string) int {
	m = make(map[string]int)
	return dfs(s)
}

func dfs(s string) int {
	if m[s] > 0 {
		return m[s]
	}
	if len(s) == 0 {
		return 1
	}
	if s[0] == '0' {
		return 0
	}
	if len(s) == 1 {
		return 1
	}
	if (s[0]-'0')*10+s[1]-'0' > 26 {
		return dfs(s[1:])
	}
	m[s] = dfs(s[1:]) + dfs(s[2:])
	return m[s]
}

92.反转链表II(2)

  • 题目

反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。
说明: 1 ≤ m ≤ n ≤ 链表长度。
示例:输入: 1->2->3->4->5->NULL, m = 2, n = 4 输出: 1->4->3->2->5->NULL
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 遍历 O(n) O(1)
02 递归 O(n) O(n)
func reverseBetween(head *ListNode, m int, n int) *ListNode {
	if m == n || head == nil {
		return head
	}
	temp := &ListNode{Next: head}
	prev := temp
	for i := 1; i < m; i++ {
		prev = prev.Next
	}
	head = prev.Next
	for i := m; i < n; i++ {
		next := head.Next
		head.Next = next.Next
		next.Next = prev.Next
		prev.Next = next
	}
	return temp.Next
}

# 2
func reverseBetween(head *ListNode, m int, n int) *ListNode {
	if m == 1 {
		return reverseN(head, n)
	}
	head.Next = reverseBetween(head.Next, m-1, n-1)
	return head
}

var next *ListNode

func reverseN(head *ListNode, n int) *ListNode {
	if n == 1 {
		next = head.Next
		return head
	}
	prev := reverseN(head.Next, n-1)
	head.Next.Next = head
	head.Next = next
	return prev
}

93.复原IP地址(2)

  • 题目

给定一个只包含数字的字符串,复原它并返回所有可能的 IP 地址格式。
有效的 IP 地址正好由四个整数(每个整数位于 0 到 255 之间组成),整数之间用 '.' 分隔。
示例:输入: "25525511135" 输出: ["255.255.11.135", "255.255.111.35"]
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 回溯 O(1) O(1)
02 暴力法 O(1) O(1)
var res []string

func restoreIpAddresses(s string) []string {
	res = make([]string, 0)
	if len(s) < 4 || len(s) > 12 {
		return nil
	}
	dfs(s, make([]string, 0), 0)
	return res
}

func dfs(s string, arr []string, level int) {
	if level == 4 {
		if len(s) == 0 {
			str := strings.Join(arr, ".")
			res = append(res, str)
		}
		return
	}
	for i := 1; i <= 3; i++ {
		if i <= len(s) {
			value, _ := strconv.Atoi(s[:i])
			if value <= 255 {
				str := s[i:]
				dfs(str, append(arr, s[:i]), level+1)
			}
			if value == 0 {
				// 避免出现001,01这种情况
				break
			}
		}
	}
}

# 2
func restoreIpAddresses(s string) []string {
	res := make([]string, 0)
	if len(s) < 4 || len(s) > 12 {
		return nil
	}
	for i := 1; i <= 3 && i < len(s)-2; i++ {
		for j := i + 1; j <= i+3 && j < len(s)-1; j++ {
			for k := j + 1; k <= j+3 && k < len(s); k++ {
				if judge(s[:i]) && judge(s[i:j]) &&
					judge(s[j:k]) && judge(s[k:]) {
					res = append(res, s[:i]+"."+s[i:j]+"."+s[j:k]+"."+s[k:])
				}
			}
		}
	}
	return res
}

func judge(s string) bool {
	if len(s) > 1 && s[0] == '0' {
		return false
	}
	value, _ := strconv.Atoi(s)
	if value > 255 {
		return false
	}
	return true
}

94.二叉树的中序遍历(3)

  • 题目

给定一个二叉树,返回它的中序 遍历。
示例:输入: [1,null,2,3]
   1
    \
     2
    /
   3
输出: [1,3,2]
进阶: 递归算法很简单,你可以通过迭代算法完成吗?
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 递归 O(n) O(n)
02 迭代 O(n) O(n)
03 递归 O(n) O(n)
func inorderTraversal(root *TreeNode) []int {
	if root == nil {
		return nil
	}
	left := inorderTraversal(root.Left)
	right := inorderTraversal(root.Right)
	res := left
	res = append(res, root.Val)
	res = append(res, right...)
	return res
}

# 2
func inorderTraversal(root *TreeNode) []int {
	if root == nil {
		return nil
	}
	stack := make([]*TreeNode, 0)
	res := make([]int, 0)
	for len(stack) > 0 || root != nil {
		for root != nil {
			stack = append(stack, root)
			root = root.Left
		}
		last := len(stack) - 1
		res = append(res, stack[last].Val)
		root = stack[last].Right
		stack = stack[:last]
	}
	return res
}

# 3
var res []int

func inorderTraversal(root *TreeNode) []int {
	res = make([]int, 0)
	dfs(root)
	return res
}

func dfs(root *TreeNode) {
	if root != nil {
		dfs(root.Left)
		res = append(res, root.Val)
		dfs(root.Right)
	}
}

95.不同的二叉搜索树II(2)

  • 题目

给定一个整数 n,生成所有由 1 ... n 为节点所组成的 二叉搜索树 。
示例:输入:3
输出:
[
  [1,null,3,2],
  [3,2,null,1],
  [3,1,null,null,2],
  [2,1,3],
  [1,null,2,null,3]
]
解释:以上的输出对应以下 5 种不同结构的二叉搜索树:
   1         3     3      2      1
    \       /     /      / \      \
     3     2     1      1   3      2
    /     /       \                 \
   2     1         2                 3
提示:
    0 <= n <= 8
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 递归 O(C(2n,n)/(n+1)) O(n)
02 动态规划 O(C(2n,n)/(n+1)) O(n^2)
func generateTrees(n int) []*TreeNode {
	if n == 0 {
		return nil
	}
	return dfs(1, n)
}

func dfs(left, right int) []*TreeNode {
	if left > right {
		return []*TreeNode{nil}
	}
	if left == right {
		return []*TreeNode{
			{Val: left},
		}
	}
	arr := make([]*TreeNode, 0)
	for i := left; i <= right; i++ {
		leftTree := dfs(left, i-1)
		rightTree := dfs(i+1, right)
		for j := 0; j < len(leftTree); j++ {
			for k := 0; k < len(rightTree); k++ {
				node := &TreeNode{Val: i}
				node.Left = leftTree[j]
				node.Right = rightTree[k]
				arr = append(arr, node)
			}
		}
	}
	return arr
}

# 2
func generateTrees(n int) []*TreeNode {
	if n == 0 {
		return nil
	}
	dp := make([][]*TreeNode, n+1)
	dp[1] = append(dp[1], &TreeNode{Val: 1})
	for i := 2; i <= n; i++ {
		for _, node := range dp[i-1]{
			root := &TreeNode{Val:i}
			root.Left = node
			dp[i] = append(dp[i], copyTree(root))
			root = node
			temp := root
			newNode := &TreeNode{Val:i}
			for temp != nil{
				newNode.Left = temp.Right
				temp.Right = newNode
				dp[i] = append(dp[i], copyTree(root))
				temp.Right = newNode.Left
				newNode.Left = nil
				temp = temp.Right
			}
		}
	}
	return dp[n]
}

func copyTree(node *TreeNode) *TreeNode {
	if node == nil {
		return nil
	}
	newNode := &TreeNode{Val: node.Val}
	newNode.Left = copyTree(node.Left)
	newNode.Right = copyTree(node.Right)
	return newNode
}

96.不同的二叉搜索树(3)

  • 题目

给定一个整数 n,求以 1 ... n 为节点组成的二叉搜索树有多少种?
示例:输入: 3 输出: 5
解释: 给定 n = 3, 一共有 5 种不同结构的二叉搜索树:
   1         3     3      2      1
    \       /     /      / \      \
     3     2     1      1   3      2
    /     /       \                 \
   2     1         2                 3
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 动态规划 O(n^2) O(n)
02 公式 O(n) O(1)
03 公式 O(n) O(1)
func numTrees(n int) int {
	dp := make([]int, n+1)
	dp[0] =1
	dp[1] =1
	for i := 2; i <= n;i++{
		for j := 1; j <= i; j++{
			dp[i] = dp[i] + dp[j-1]*dp[i-j]
		}
	}
	return dp[n]
}

#
/*
C0 = 1
Cn+1 = 2(2n+1)/(n+2) * Cn
*/
func numTrees(n int) int {
	c := 1
	for i := 1; i < n;i++{
		c = c * 2 * (2*i+1)/(i+2)
	}
	return c
}

#
func numTrees(n int) int {
	c := 1
	for i := 1; i <= n;i++{
		c = c * (n+i)/i
	}
	return c/(n+1)
}

98.验证二叉搜索树(5)

  • 题目

给定一个二叉树,判断其是否是一个有效的二叉搜索树。
假设一个二叉搜索树具有如下特征:
    节点的左子树只包含小于当前节点的数。
    节点的右子树只包含大于当前节点的数。
    所有左子树和右子树自身必须也是二叉搜索树。
示例 1:输入:
    2
   / \
  1   3
输出: true
示例 2:输入:
    5
   / \
  1   4
     / \
    3   6
输出: false
解释: 输入为: [5,1,4,null,null,3,6]。
     根节点的值为 5 ,但是其右子节点值为 4 。
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 递归 O(n) O(log(n))
02 递归 O(n) O(n)
03 迭代 O(n) O(n)
04 迭代 O(n) O(n)
05 递归 O(n) O(log(n))
func isValidBST(root *TreeNode) bool {
	return dfs(root, math.MinInt64, math.MaxInt64)
}

func dfs(root *TreeNode, left, right int) bool {
	if root == nil {
		return true
	}
	if left >= root.Val || right <= root.Val {
		return false
	}
	return dfs(root.Left, left, root.Val) && dfs(root.Right, root.Val, right)
}

# 2
var res []int

func isValidBST(root *TreeNode) bool {
	res = make([]int, 0)
	dfs(root)
	for i := 0; i < len(res)-1; i++ {
		if res[i] >= res[i+1] {
			return false
		}
	}
	return true
}

func dfs(root *TreeNode) {
	if root != nil {
		dfs(root.Left)
		res = append(res, root.Val)
		dfs(root.Right)
	}
}

# 3
func isValidBST(root *TreeNode) bool {
	if root == nil {
		return true
	}
	stack := make([]*TreeNode, 0)
	res := make([]int, 0)
	for len(stack) > 0 || root != nil {
		for root != nil {
			stack = append(stack, root)
			root = root.Left
		}
		last := len(stack) - 1
		res = append(res, stack[last].Val)
		root = stack[last].Right
		stack = stack[:last]
	}
	for i := 0; i < len(res)-1; i++ {
		if res[i] >= res[i+1] {
			return false
		}
	}
	return true
}

# 4
func isValidBST(root *TreeNode) bool {
	if root == nil {
		return true
	}
	stack := make([]*TreeNode, 0)
	pre := math.MinInt64
	for len(stack) > 0 || root != nil {
		for root != nil {
			stack = append(stack, root)
			root = root.Left
		}
		last := len(stack) - 1
		if stack[last].Val <= pre {
			return false
		}
		pre = stack[last].Val
		root = stack[last].Right
		stack = stack[:last]
	}
	return true
}

# 5
var pre int

func isValidBST(root *TreeNode) bool {
	pre = math.MinInt64
	return dfs(root)
}

func dfs(root *TreeNode) bool {
	if root == nil {
		return true
	}
	if dfs(root.Left) == false {
		return false
	}
	if root.Val <= pre {
		return false
	}
	pre = root.Val
	return dfs(root.Right)
}

0001-1000-Hard

4.寻找两个正序数组的中位数(4)

  • 题目

给定两个大小为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。
请你找出这两个正序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。
你可以假设 nums1 和 nums2 不会同时为空。
示例 1:nums1 = [1, 3] nums2 = [2]
则中位数是 2.0
示例 2:nums1 = [1, 2] nums2 = [3, 4]
则中位数是 (2 + 3)/2 = 2.5
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 排序 O(nlog(n)) O(n)
02 二分查找 O(log(n)) O(1)
03 遍历 O(n) O(1)
04 二分查找 O(log(n)) O(1)
func findMedianSortedArrays(nums1 []int, nums2 []int) float64 {
	nums1 = append(nums1, nums2...)
	sort.Ints(nums1)
	if len(nums1)%2 == 1 {
		return float64(nums1[len(nums1)/2])
	}
	return float64(nums1[len(nums1)/2]+nums1[len(nums1)/2-1]) / 2
}

# 2
func findMedianSortedArrays(nums1 []int, nums2 []int) float64 {
	total := len(nums1) + len(nums2)
	if total%2 == 1 {
		mid := total / 2
		return float64(getKth(nums1, nums2, mid+1))
	}
	mid1, mid2 := total/2-1, total/2
	return float64(getKth(nums1, nums2, mid1+1)+getKth(nums1, nums2, mid2+1)) / 2.0
}

func getKth(nums1 []int, nums2 []int, k int) int {
	a, b := 0, 0
	for {
		if a == len(nums1) {
			return nums2[b+k-1]
		}
		if b == len(nums2) {
			return nums1[a+k-1]
		}
		if k == 1 {
			return min(nums1[a], nums2[b])
		}
		mid := k / 2
		newA := min(a+mid, len(nums1)) - 1
		newB := min(b+mid, len(nums2)) - 1
		valueA, valueB := nums1[newA], nums2[newB]
		if valueA < valueB {
			k = k - (newA - a + 1)
			a = newA + 1
		} else {
			k = k - (newB - b + 1)
			b = newB + 1
		}
	}
}

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

# 3
func findMedianSortedArrays(nums1 []int, nums2 []int) float64 {
	total := len(nums1) + len(nums2)
	a, b := total/2, (total-1)/2
	count := 0
	res := 0
	for i, j := 0, 0; i < len(nums1) || j < len(nums2); count++ {
		if i < len(nums1) && (j == len(nums2) || nums1[i] < nums2[j]) {
			if count == a {
				res = res + nums1[i]
			}
			if count == b {
				res = res + nums1[i]
			}
			i++
		} else {
			if count == a {
				res = res + nums2[j]
			}
			if count == b {
				res = res + nums2[j]
			}
			j++
		}
	}
	return float64(res) / 2
}

# 4
func findMedianSortedArrays(nums1 []int, nums2 []int) float64 {
	n, m := len(nums1), len(nums2)
	if n > m {
		return findMedianSortedArrays(nums2, nums1)
	}
	left, right := 0, n
	a, b := 0, 0
	for left <= right {
		// 左半部分最大的值小于等于右半部分最小的值: max(A[i-1],B[j-1])) <= min(A[i],B[j]))
		i := left + (right-left)/2 // i,j分别对num1,num2的划分
		j := (n+m+1)/2 - i         // i+j == (n+m+1)/2
		// 偶数求a=>max(A[i-1],B[j-1])) b=>min(A[i],B[j]))
		// 奇数求a=>max(A[i-1],B[j-1]))
		if j != 0 && i != n && nums1[i] < nums2[j-1] {
			left = i + 1
		} else if i != 0 && j != m && nums1[i-1] > nums2[j] {
			right = i - 1
		} else {
			if i == 0 {
				a = nums2[j-1]
			} else if j == 0 {
				a = nums1[i-1]
			} else {
				a = max(nums1[i-1], nums2[j-1])
			}
			if (n+m)%2 == 1 {
				return float64(a)
			}
			if i == n {
				b = nums2[j]
			} else if j == m {
				b = nums1[i]
			} else {
				b = min(nums1[i], nums2[j])
			}
			return float64(a+b) / 2.0
		}
	}
	return 0.0
}

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

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

10.正则表达式匹配(3)

  • 题目

给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 '.' 和 '*' 的正则表达式匹配。
'.' 匹配任意单个字符
'*' 匹配零个或多个前面的那一个元素
所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。
说明:
    s 可能为空,且只包含从 a-z 的小写字母。
    p 可能为空,且只包含从 a-z 的小写字母,以及字符 . 和 *。
示例 1:输入:s = "aa" p = "a" 输出: false
解释: "a" 无法匹配 "aa" 整个字符串。
示例 2:输入: s = "aa" p = "a*" 输出: true
解释: 因为 '*' 代表可以匹配零个或多个前面的那一个元素, 在这里前面的元素就是 'a'。
因此,字符串 "aa" 可被视为 'a' 重复了一次。
示例 3:输入: s = "ab" p = ".*" 输出: true
解释: ".*" 表示可匹配零个或多个('*')任意字符('.')。
示例 4:输入:s = "aab"p = "c*a*b" 输出: true
解释: 因为 '*' 表示零个或多个,这里 'c' 为 0 个, 'a' 被重复一次。因此可以匹配字符串 "aab"。
示例 5:输入:s = "mississippi"p = "mis*is*p*." 输出: false
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 递归 O(n) O(n)
02 动态规划 O(n^2) O(n^2)
03 递归 O(n) O(n)
func isMatch(s string, p string) bool {
	return dfs(s, p, 0, 0)
}

func dfs(s string, p string, i, j int) bool {
	if i >= len(s) && j >= len(p) {
		return true
	}
	if i <= len(s) && j >= len(p) {
		return false
	}
	if j+1 < len(p) && p[j+1] == '*' {
		if (i < len(s) && p[j] == s[i]) || (p[j] == '.' && i < len(s)) {
			return dfs(s, p, i+1, j+2) ||
				dfs(s, p, i+1, j) ||
				dfs(s, p, i, j+2)
		} else {
			return dfs(s, p, i, j+2)
		}
	}
	if (i < len(s) && s[i] == p[j]) || (p[j] == '.' && i < len(s)) {
		return dfs(s, p, i+1, j+1)
	}
	return false
}

# 2
func isMatch(s string, p string) bool {
	// dp[i][j]表示p[:i]能否正则匹配s[:j]
	dp := make([][]bool, len(p)+1)
	for i := 0; i < len(p)+1; i++ {
		dp[i] = make([]bool, len(s)+1)
	}
	// 1.初始化
	dp[0][0] = true
	for i := 2; i < len(p)+1; i++ {
		if i%2 == 0 && p[i-1] == '*' {
			dp[i][0] = dp[i-2][0]
		}
	}
	// 2.dp状态转移
	for i := 1; i < len(p)+1; i++ {
		for j := 1; j < len(s)+1; j++ {
			// 2.1 相同或者 .
			if p[i-1] == s[j-1] || p[i-1] == '.' {
				dp[i][j] = dp[i-1][j-1]
			} else if p[i-1] == '*' {
				if i > 1 {
					if p[i-2] == s[j-1] || p[i-2] == '.' {
						dp[i][j] = dp[i][j-1] || dp[i-2][j-1] || dp[i-2][j]
					} else {
						dp[i][j] = dp[i-2][j]
					}
				}
			}
		}
	}
	return dp[len(p)][len(s)]
}

# 3
func isMatch(s string, p string) bool {
	if len(s) == 0 && len(p) == 0 {
		return true
	} else if len(p) == 0 {
		return false
	}
	match := false
	// 正常匹配条件=>相等,或者 p[0]等于.就不用管s[0]
	if len(s) > 0 && (s[0] == p[0] || p[0] == '.') {
		match = true
	}
	// 匹配多个 就把 s 往后移1位,注意p不移动
	// 匹配0个 就把 p 往后移2位,相当于p的*当前作废
	if len(p) > 1 && p[1] == '*' {
		return (match && isMatch(s[1:], p)) || isMatch(s, p[2:])
	}
	// 匹配当前成功,同时往后移
	return match && isMatch(s[1:], p[1:])
}

23.合并K个排序链表(4)

  • 题目

合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。
示例:输入:
[
  1->4->5,
  1->3->4,
  2->6
]
输出: 1->1->2->3->4->4->5->6
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 顺序合并 O(n^2) O(1)
02 归并(分治)合并 O(nlog(n)) O(log(n))
03 堆辅助 O(nlog(n)) O(log(n))
04 自定义排序 O(nlog(n)) O(n)
func mergeKLists(lists []*ListNode) *ListNode {
	if len(lists) == 0 {
		return nil
	}
	temp := &ListNode{}
	for i := 0; i < len(lists); i++ {
		temp.Next = mergeTwoLists(temp.Next, lists[i])
	}
	return temp.Next
}

func mergeTwoLists(l1 *ListNode, l2 *ListNode) *ListNode {
	res := &ListNode{}
	temp := res
	for l1 != nil && l2 != nil {
		if l1.Val < l2.Val {
			temp.Next = l1
			l1 = l1.Next
		} else {
			temp.Next = l2
			l2 = l2.Next
		}
		temp = temp.Next
	}
	if l1 != nil {
		temp.Next = l1
	} else {
		temp.Next = l2
	}
	return res.Next
}

# 2
func mergeKLists(lists []*ListNode) *ListNode {
	if len(lists) == 0 {
		return nil
	}
	if len(lists) == 1 {
		return lists[0]
	}
	first := mergeKLists(lists[:len(lists)/2])
	second := mergeKLists(lists[len(lists)/2:])
	return mergeTwoLists(first, second)
}

func mergeTwoLists(l1 *ListNode, l2 *ListNode) *ListNode {
	res := &ListNode{}
	temp := res
	for l1 != nil && l2 != nil {
		if l1.Val < l2.Val {
			temp.Next = l1
			l1 = l1.Next
		} else {
			temp.Next = l2
			l2 = l2.Next
		}
		temp = temp.Next
	}
	if l1 != nil {
		temp.Next = l1
	} else {
		temp.Next = l2
	}
	return res.Next
}

# 3
func mergeKLists(lists []*ListNode) *ListNode {
	if len(lists) == 0 {
		return nil
	}
	var h IntHeap
	heap.Init(&h)
	for i := 0; i < len(lists); i++ {
		if lists[i] != nil {
			heap.Push(&h, lists[i])
		}
	}
	res := &ListNode{}
	temp := res
	for h.Len() > 0 {
		minItem := heap.Pop(&h).(*ListNode)
		temp.Next = minItem
		temp = temp.Next
		if minItem.Next != nil {
			heap.Push(&h, minItem.Next)
		}
	}
	return res.Next
}

type IntHeap []*ListNode

func (h IntHeap) Len() int            { return len(h) }
func (h IntHeap) Less(i, j int) bool  { return h[i].Val < h[j].Val }
func (h IntHeap) Swap(i, j int)       { h[i], h[j] = h[j], h[i] }
func (h *IntHeap) Push(x interface{}) { *h = append(*h, x.(*ListNode)) }
func (h *IntHeap) Pop() interface{} {
	old := *h
	n := len(old)
	x := old[n-1]
	*h = old[0 : n-1]
	return x
}

# 4
func mergeKLists(lists []*ListNode) *ListNode {
	if len(lists) == 0 {
		return nil
	}
	arr := make([]*ListNode, 0)
	for i := 0; i < len(lists); i++ {
		temp := lists[i]
		for temp != nil {
			arr = append(arr, temp)
			temp = temp.Next
		}
	}
	if len(arr) == 0 {
		return nil
	}
	sort.Slice(arr, func(i, j int) bool {
		return arr[i].Val < arr[j].Val
	})
	for i := 0; i < len(arr)-1; i++ {
		arr[i].Next = arr[i+1]
	}
	arr[len(arr)-1].Next = nil
	return arr[0]
}

25.K个一组翻转链表(4)

  • 题目

给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。
k 是一个正整数,它的值小于或等于链表的长度。
如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
示例:
给你这个链表:1->2->3->4->5
当 k = 2 时,应当返回: 2->1->4->3->5
当 k = 3 时,应当返回: 3->2->1->4->5
说明:
    你的算法只能使用常数的额外空间。
    你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 递归 O(n) O(n)
02 递归 O(n) O(n)
03 遍历 O(n) O(1)
04 遍历 O(n) O(1)
func reverseKGroup(head *ListNode, k int) *ListNode {
	length := getLength(head)
	if length < k || k <= 1 {
		return head
	}
	pre := &ListNode{}
	cur := head
	for i := 0; i < k; i++ {
		temp := cur
		cur = cur.Next
		temp.Next = pre
		pre = temp
	}
	head.Next = reverseKGroup(cur, k)
	return pre
}

func getLength(head *ListNode) int {
	if head == nil {
		return 0
	}
	temp := head
	res := 0
	for temp != nil {
		res++
		temp = temp.Next
	}
	return res
}

# 2
func reverseKGroup(head *ListNode, k int) *ListNode {
	res := 0
	temp := head
	for temp != nil {
		res++
		temp = temp.Next
	}
	if res < k || k <= 1 {
		return head
	}
	pre := &ListNode{}
	cur := head
	for i := 0; i < k; i++ {
		next := cur.Next
		cur.Next = pre
		pre = cur
		cur = next
	}
	head.Next = reverseKGroup(cur, k)
	return pre
}

# 3
func reverseKGroup(head *ListNode, k int) *ListNode {
	res := &ListNode{Next: head}
	prev := res
	for head != nil {
		tail := prev
		for i := 0; i < k; i++ {
			tail = tail.Next
			if tail == nil {
				return res.Next
			}
		}
		next := tail.Next
		head, tail = reverse(head, tail)
		prev.Next = head
		tail.Next = next
		prev = tail
		head = tail.Next
	}
	return res.Next
}

func reverse(head, tail *ListNode) (*ListNode, *ListNode) {
	prev := tail.Next
	temp := head
	for prev != tail {
		next := temp.Next
		temp.Next = prev
		prev = temp
		temp = next
	}
	return tail, head
}

# 4
func reverseKGroup(head *ListNode, k int) *ListNode {
	res := &ListNode{Next: head}
	prev, end := res, res
	for end.Next != nil {
		for i := 0; i < k && end != nil; i++ {
			end = end.Next
		}
		if end == nil {
			break
		}
		start := prev.Next         // 开始的位置
		next := end.Next           // 结束的下一个位置
		end.Next = nil             // 断开尾部连接
		prev.Next = reverse(start) // 反转后接到prev.Next
		start.Next = next          // start的指针指向下一个开头(此时start已经是反转的最后一个节点)
		prev = start               // 已经处理后的最后一个节点
		end = prev                 // end也移动到prev
	}
	return res.Next
}

func reverse(head *ListNode) *ListNode {
	var result *ListNode
	for head != nil {
		temp := head.Next
		head.Next = result
		result = head
		head = temp
	}
	return result
}

30.串联所有单词的子串(2)

  • 题目

给定一个字符串 s 和一些长度相同的单词 words。
找出 s 中恰好可以由 words 中所有单词串联形成的子串的起始位置。
注意子串要与 words 中的单词完全匹配,中间不能有其他字符,但不需要考虑 words 中单词串联的顺序。
示例 1:输入:s = "barfoothefoobarman",words = ["foo","bar"] 输出:[0,9]
解释:从索引 0 和 9 开始的子串分别是 "barfoo" 和 "foobar" 。
输出的顺序不重要, [9,0] 也是有效答案。
示例 2:输入:s = "wordgoodgoodgoodbestword",words = ["word","good","best","word"]输出:[]
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 遍历 O(n^2) O(n)
02 滑动窗口 O(n^2) O(n)
func findSubstring(s string, words []string) []int {
	res := make([]int, 0)
	length,n := len(s),len(words)
	if length == 0 || n == 0 || len(words[0]) == 0 {
		return res
	}
	single := len(words[0])
	m := make(map[string]int)
	for i := 0; i < len(words); i++ {
		m[words[i]]++
	}
	for i := 0; i <= length-n*single; i++ {
		temp := make(map[string]int)
		for j := 0; j < n; j++ {
			l := i + j*single
			str := s[l : l+single]
			if _, ok := m[str]; !ok {
				break
			}
			temp[str]++
			if temp[str] > m[str] {
				break
			}
			if compare(m, temp) == true {
				res = append(res, i)
				break
			}
		}
	}
	return res
}

func compare(m1, m2 map[string]int) bool {
	if len(m1) != len(m2) {
		return false
	}
	for k, v := range m1 {
		if m2[k] != v {
			return false
		}
	}
	return true
}

# 2
func findSubstring(s string, words []string) []int {
	res := make([]int, 0)
	length := len(s)
	n := len(words)
	if length == 0 || n == 0 || len(words[0]) == 0 {
		return res
	}
	single := len(words[0])
	m := make(map[string]int)
	for i := 0; i < len(words); i++ {
		m[words[i]]++
	}
	for i := 0; i < single; i++ {
		left, right, count := i, i, 0
		temp := make(map[string]int)
		for right+single <= length {
			str := s[right : right+single]
			right = right + single
			if m[str] > 0 {
				temp[str]++
				if temp[str] == m[str] {
					count++
				}
			}
			if right-left == n*single {
				if count == len(m) {
					res = append(res, left)
				}
				leftStr := s[left : left+single]
				left = left + single
				if m[leftStr] > 0 {
					if temp[leftStr] == m[leftStr] {
						count--
					}
					temp[leftStr]--
				}
			}
		}
	}
	return res
}

32.最长有效括号(4)

  • 题目

给定一个只包含 '(' 和 ')' 的字符串,找出最长的包含有效括号的子串的长度。
示例 1:输入: "(()"输出: 2
解释: 最长有效括号子串为 "()"
示例 2:输入: ")()())" 输出: 4
解释: 最长有效括号子串为 "()()"
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 栈辅助 O(n) O(n)
02 动态规划 O(n) O(n)
03 遍历 O(n) O(1)
04 暴力法 O(n^2) O(1)
func longestValidParentheses(s string) int {
	res := 0
	stack := make([]int, 0)
	stack = append(stack, -1)
	for i := 0; i < len(s); i++ {
		if s[i] == '(' {
			stack = append(stack, i)
		} else {
			stack = stack[:len(stack)-1] // 弹出栈顶元素表示匹配了当前右括号
			if len(stack) == 0 {         // 没有匹配到左括号,存入最后一个没有被匹配到的右括号下标
				stack = append(stack, i)
			} else {
				res = max(res, i-stack[len(stack)-1])
			}
		}
	}
	return res
}

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

# 2
func longestValidParentheses(s string) int {
	res := 0
	dp := make([]int, len(s))
	for i := 1; i < len(s); i++ {
		if s[i] == ')' {
			// '()' 匹配到
			if s[i-1] == '(' {
				if i < 2 {
					dp[i] = 2
				} else {
					dp[i] = dp[i-2] + 2
				}
			} else {
				// '))'情况
				if i-dp[i-1] > 0 && s[i-dp[i-1]-1] == '(' {
					if i-dp[i-1] < 2 {
						dp[i] = dp[i-1] + 2
					} else {
						dp[i] = dp[i-1] + dp[i-dp[i-1]-2] + 2
					}
				}
			}
		}
		res = max(res, dp[i])
	}
	return res
}

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

# 3
func longestValidParentheses(s string) int {
	res := 0
	left, right := 0, 0
	for i := 0; i < len(s); i++ {
		if s[i] == '(' {
			left++
		} else {
			right++
		}
		if left == right {
			res = max(res, 2*left)
		} else if right > left {
			left, right = 0, 0
		}
	}
	left, right = 0, 0
	for i := len(s) - 1; i >= 0; i-- {
		if s[i] == '(' {
			left++
		} else {
			right++
		}
		if left == right {
			res = max(res, 2*left)
		} else if left > right {
			left, right = 0, 0
		}
	}
	return res
}

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

# 4
func longestValidParentheses(s string) int {
	res := 0
	for i := 0; i < len(s); i++ {
		count := 0
		for j := i; j < len(s); j++ {
			if s[j] == '(' {
				count++
			} else {
				count--
			}
			if count < 0 {
				break
			}
			if count == 0 {
				res = max(res, j+1-i)
			}
		}
	}
	return res
}

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

37.解数独(2)

  • 题目

编写一个程序,通过已填充的空格来解决数独问题。
一个数独的解法需遵循如下规则:
    数字 1-9 在每一行只能出现一次。
    数字 1-9 在每一列只能出现一次。
    数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。
空白格用 '.' 表示。
一个数独。
答案被标成红色。
Note:给定的数独序列只包含数字 1-9 和字符 '.' 。
    你可以假设给定的数独只有唯一解。
    给定数独永远是 9x9 形式的。
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 回溯 O((9!)^9) O(1)
02 回溯 O((9!)^9) O(1)
var rows, cols, arrs [9][9]int

func solveSudoku(board [][]byte) {
	rows = [9][9]int{}
	cols = [9][9]int{}
	arrs = [9][9]int{}
	for i := 0; i < 9; i++ {
		for j := 0; j < 9; j++ {
			if board[i][j] != '.' {
				num := board[i][j] - '1'
				index := (i/3)*3 + j/3
				rows[i][num] = 1
				cols[j][num] = 1
				arrs[index][num] = 1
			}
		}
	}
	dfs(board, 0)
}

func dfs(board [][]byte, index int) bool {
	if index == 81 {
		return true
	}
	row := index / 9
	col := index % 9
	c := (row/3)*3 + col/3
	if board[row][col] != '.' {
		return dfs(board, index+1)
	}
	for i := 0; i < 9; i++ {
		if rows[row][i] == 1 || cols[col][i] == 1 || arrs[c][i] == 1 {
			continue
		}
		board[row][col] = byte(i + '1')
		rows[row][i], cols[col][i], arrs[c][i] = 1, 1, 1
		if dfs(board, index+1) == true {
			return true
		}
		rows[row][i], cols[col][i], arrs[c][i] = 0, 0, 0
		board[row][col] = '.'
	}
	return false
}

# 2
func solveSudoku(board [][]byte) {
	dfs(board, 0)
}

func dfs(board [][]byte, index int) bool {
	if index == 81 {
		return true
	}
	row := index / 9
	col := index % 9
	if board[row][col] != '.' {
		return dfs(board, index+1)
	}
	for i := 0; i < 9; i++ {
		board[row][col] = byte(i + '1')
		if isValidSudoku(board) == false {
			board[row][col] = '.'
			continue
		}
		if dfs(board, index+1) == true {
			return true
		}
		board[row][col] = '.'
	}
	return false
}

func isValidSudoku(board [][]byte) bool {
	var row, col, arr [9][9]int
	for i := 0; i < 9; i++ {
		for j := 0; j < 9; j++ {
			if board[i][j] != '.' {
				num := board[i][j] - '1'
				index := (i/3)*3 + j/3
				if row[i][num] == 1 || col[j][num] == 1 || arr[index][num] == 1 {
					return false
				}
				row[i][num] = 1
				col[j][num] = 1
				arr[index][num] = 1
			}
		}
	}
	return true
}

41.缺失的第一个正数(5)

  • 题目

给你一个未排序的整数数组,请你找出其中没有出现的最小的正整数。
示例 1:输入: [1,2,0] 输出: 3
示例 2:输入: [3,4,-1,1]输出: 2
示例 3:输入: [7,8,9,11,12]输出: 1
提示:你的算法的时间复杂度应为O(n),并且只能使用常数级别的额外空间。
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 标负 O(n) O(1)
02 置换 O(n) O(1)
03 哈希辅助 O(n) O(n)
04 暴力法 O(n^2) O(1)
05 O(n) O(n)
func firstMissingPositive(nums []int) int {
	n := len(nums)
	for i := 0; i < n; i++ {
		// 非正数处理
		if nums[i] <= 0 {
			nums[i] = n + 1
		}
	}
	for i := 0; i < n; i++ {
		value := abs(nums[i])
		// 标负
		if value <= n {
			nums[value-1] = -abs(abs(nums[value-1]))
		}
	}
	for i := 0; i < n; i++ {
		if nums[i] > 0 {
			return i + 1
		}
	}
	return n + 1
}

func abs(a int) int {
	if a >= 0 {
		return a
	}
	return -a
}

# 2
func firstMissingPositive(nums []int) int {
	n := len(nums)
	for i := 0; i < n; i++ {
		for nums[i] > 0 && nums[i] <= n && nums[nums[i]-1] != nums[i] {
			nums[i], nums[nums[i]-1] = nums[nums[i]-1], nums[i]
		}
	}
	for i := 0; i < n; i++ {
		if nums[i] != i+1 {
			return i + 1
		}
	}
	return n + 1
}

# 3
func firstMissingPositive(nums []int) int {
	n := len(nums)
	m := make(map[int]int)
	for i := 0; i < n; i++ {
		m[nums[i]] = 1
	}
	for i := 1; i <= n; i++ {
		if m[i] == 0 {
			return i
		}
	}
	return n + 1
}

# 4
func firstMissingPositive(nums []int) int {
	n := len(nums)
	for i := 1; i <= n; i++ {
		flag := false
		for j := 0; j < n; j++ {
			if i == nums[j] {
				flag = true
				break
			}
		}
		if flag == false {
			return i
		}
	}
	return n + 1
}

# 5
func firstMissingPositive(nums []int) int {
	n := len(nums)
	arr := make([]int, n+1)
	for i := 0; i < n; i++ {
		if 1 <= nums[i] && nums[i] <= n {
			arr[nums[i]] = 1
		}
	}
	for i := 1; i <= n; i++ {
		if arr[i] == 0 {
			return i
		}
	}
	return n + 1
}

42.接雨水(4)

  • 题目

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,
在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 感谢 Marcos 贡献此图。
示例:输入: [0,1,0,2,1,0,1,3,2,1,2,1]输出: 6
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 暴力法 O(n^2) O(1)
02 数组辅助 O(n) O(n)
03 栈辅助 O(n) O(n)
04 双指针 O(n) O(1)
func trap(height []int) int {
	res := 0
	for i := 0; i < len(height); i++ {
		left, right := 0, 0
		for j := i; j >= 0; j-- {
			left = max(left, height[j])
		}
		for j := i; j < len(height); j++ {
			right = max(right, height[j])
		}
		// 当前坐标形成的面积=(min(左边最高,右边最高)-当前高度) * 宽度(1,可省略)
		area := min(left, right) - height[i]
		res = res + area
	}
	return res
}

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

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

# 2
func trap(height []int) int {
	res := 0
	if len(height) == 0{
		return 0
	}
	left := make([]int, len(height))
	right := make([]int, len(height))
	left[0] = height[0]
	right[len(right)-1] = height[len(height)-1]
	for i := 1; i < len(height); i++ {
		left[i] = max(height[i], left[i-1])
	}
	for i := len(height) - 2; i >= 0; i-- {
		right[i] = max(height[i], right[i+1])
	}
	for i := 0; i < len(height); i++ {
		// 当前坐标形成的面积=(min(左边最高,右边最高)-当前高度) * 宽度(1,可省略)
		area := min(left[i], right[i]) - height[i]
		res = res + area
	}
	return res
}

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

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

# 3
func trap(height []int) int {
	res := 0
	stack := make([]int, 0)
	for i := 0; i < len(height); i++ {
		for len(stack) > 0 && height[i] > height[stack[len(stack)-1]] {
			bottom := height[stack[len(stack)-1]]
			stack = stack[:len(stack)-1]
			if len(stack) > 0 {
				prev := stack[len(stack)-1]
				// 横着的面积=长(min(height[i], height[prev])-bottom)*宽(i-prev-1)
				h := min(height[i], height[prev]) - bottom
				w := i - prev - 1
				area := h * w
				res = res + area
			}
		}
		stack = append(stack, i)
	}
	return res
}

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

# 4
func trap(height []int) int {
	res := 0
	if len(height) == 0 {
		return 0
	}
	left := 0
	right := len(height) - 1
	leftMax := 0  // 左边的最大值
	rightMax := 0 // 右边的最大值
	for left < right {
		// 当前坐标形成的面积=(min(左边最高,右边最高)-当前高度) * 宽度(1,可省略)
		// 选择高度低的一边处理并求最大值, 说明当前侧最大值小于另一侧
		if height[left] < height[right] {
			// 也可以写成这样
			// leftMax = max(leftMax, height[left])
			// res = res + leftMax - height[left]
			if height[left] >= leftMax { // 递增无法蓄水
				leftMax = height[left]
			} else {
				res = res + leftMax - height[left]
			}
			left++
		} else {
			// 也可以写成这样
			// rightMax = max(rightMax, height[right])
			// res = res + rightMax - height[right]
			if height[right] >= rightMax { // 递减无法蓄水
				rightMax = height[right]
			} else {
				res = res + rightMax - height[right]
			}
			right--
		}
	}
	return res
}

44.通配符匹配(3)

  • 题目

给定一个字符串 (s) 和一个字符模式 (p) ,实现一个支持 '?' 和 '*' 的通配符匹配。
'?' 可以匹配任何单个字符。
'*' 可以匹配任意字符串(包括空字符串)。
两个字符串完全匹配才算匹配成功。
说明:s 可能为空,且只包含从 a-z 的小写字母。
    p 可能为空,且只包含从 a-z 的小写字母,以及字符 ? 和 *。
示例 1: 输入:s = "aa" p = "a" 输出: false
解释: "a" 无法匹配 "aa" 整个字符串。
示例 2: 输入: s = "aa" p = "*" 输出: true
解释: '*' 可以匹配任意字符串。
示例 3:输入: s = "cb" p = "?a" 输出: false
解释: '?' 可以匹配 'c', 但第二个 'a' 无法匹配 'b'。
示例 4:输入:s = "adceb" p = "*a*b" 输出: true
解释: 第一个 '*' 可以匹配空字符串, 第二个 '*' 可以匹配字符串 "dce".
示例 5:输入:s = "acdcb" p = "a*c?b" 输出: false
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 动态规划 O(n^2) O(n^2)
02 递归 O(n^2) O(n^2)
03 贪心 O(n^2) O(1)
func isMatch(s string, p string) bool {
	n, m := len(s), len(p)
	dp := make([][]bool, n+1)
	for i := 0; i <= n; i++ {
		dp[i] = make([]bool, m+1)
	}
	dp[0][0] = true
	for i := 1; i <= m; i++ {
		if p[i-1] == '*' { // 可以匹配任意字符串(包括空字符串)
			dp[0][i] = true
		} else {
			break
		}
	}
	for i := 1; i <= n; i++ {
		for j := 1; j <= m; j++ {
			if p[j-1] == '*' {
				// dp[i][j-1]=>不使用这个*,dp[i-1][j]=>使用这个*
				dp[i][j] = dp[i][j-1] || dp[i-1][j]
			} else if p[j-1] == '?' || s[i-1] == p[j-1] {
				dp[i][j] = dp[i-1][j-1]
			}
		}
	}
	return dp[n][m]
}

# 2
var dp [][]int

func isMatch(s string, p string) bool {
	n, m := len(s), len(p)
	dp = make([][]int, n+1)
	for i := 0; i <= n; i++ {
		dp[i] = make([]int, m+1)
	}
	return dfs(s, p, 0, 0)
}

func dfs(s, p string, i, j int) bool {
	if i == len(s) && j == len(p) {
		return true
	}
	if dp[i][j] > 0 {
		if dp[i][j] == 1 {
			return false
		} else {
			return true
		}
	}
	if i >= len(s) {
		return p[j] == '*' && dfs(s, p, i, j+1)
	}
	if j >= len(p) {
		return false
	}
	res := false
	if p[j] == '*' {
		res = dfs(s, p, i+1, j) || dfs(s, p, i, j+1)
	} else {
		res = (s[i] == p[j] || p[j] == '?') && dfs(s, p, i+1, j+1)
	}
	if res == true {
		dp[i][j] = 2
	} else {
		dp[i][j] = 1
	}
	return res
}

# 3
func isMatch(s string, p string) bool {
	i, j := 0, 0
	start, last := 0, 0
	for i = 0; i < len(s); {
		if j < len(p) && (s[i] == p[j] || p[j] == '?') {
			i++
			j++
		} else if j < len(p) && p[j] == '*' {
			last = i  // 记录s的位置
            j++
			start = j // 记录*的位置
		} else if start != 0 {
			last++
			i = last // 更新到记录位置的下一个
			j = start
		} else {
			return false
		}
	}
	for ; j < len(p) && p[j] == '*'; j++ {
	}
	return j == len(p)
}

45.跳跃游戏II(4)

  • 题目

给定一个非负整数数组,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
你的目标是使用最少的跳跃次数到达数组的最后一个位置。
示例:输入: [2,3,1,1,4] 输出: 2
解释: 跳到最后一个位置的最小跳跃数是 2。
     从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。
说明:假设你总是可以到达数组的最后一个位置。
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 遍历 O(n^2) O(1)
02 遍历 O(n) O(1)
03 动态规划 O(n^2) O(n)
04 迭代 O(n^2) O(n)
func jump(nums []int) int {
	last := len(nums) - 1
	res := 0
	for last > 0 {
		// 从前往后,找到第一个一步能走到终点的,更新终点的位置
		for i := 0; i < last; i++ {
			if i+nums[i] >= last {
				last = i
				res++
				break
			}
		}
	}
	return res
}

# 2
func jump(nums []int) int {
	res := 0
	end := 0
	maxValue := 0
	for i := 0; i < len(nums)-1; i++ {
		maxValue = max(maxValue, i+nums[i])
		if i == end {
			end = maxValue
			res++
		}
	}
	return res
}

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

# 3
func jump(nums []int) int {
	dp := make([]int, len(nums))
	dp[0] = 0
	for i := 1; i < len(nums); i++ {
		dp[i] = i
		for j := 0; j < i; j++ {
			if nums[j]+j >= i {
				dp[i] = min(dp[i], dp[j]+1)
			}
		}
	}
	return dp[len(nums)-1]
}

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

# 4
func jump(nums []int) int {
	if len(nums) <= 1 {
		return 0
	}
	dp := make([]int, len(nums))
	for i := 1; i < len(nums); i++ {
		dp[i] = math.MaxInt32
	}
	dp[0] = 0
	for i := 0; i < len(nums)-1; i++ {
		if i+nums[i] >= len(nums)-1 {
			return dp[i] + 1
		}
		for j := i + 1; j <= i+nums[i]; j++ {
			if j < len(nums) {
				dp[j] = min(dp[j], dp[i]+1)
			} else {
				break
			}
		}
	}
	return dp[len(nums)-1]
}

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

51.N皇后(3)

  • 题目

n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
上图为 8 皇后问题的一种解法。
给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。
每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。
示例:
输入: 4
输出: [
 [".Q..",  // 解法 1
  "...Q",
  "Q...",
  "..Q."],

 ["..Q.",  // 解法 2
  "Q...",
  "...Q",
  ".Q.."]
]
解释: 4皇后问题存在两个不同的解法。
提示:
    皇后,是国际象棋中的棋子,意味着国王的妻子。皇后只做一件事,那就是“吃子”。
    当她遇见可以吃的棋子时,就迅速冲上去吃掉棋子。当然,她横、竖、斜都可走一到七步,可进可退。
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 回溯 O(n^n) O(n^2)
02 回溯 O(n^n) O(n^2)
03 回溯 O(n^n) O(n^2)
var res [][]string

func solveNQueens(n int) [][]string {
	res = make([][]string, 0)
	// 初始化棋盘
	arr := make([][]string, n)
	for i := 0; i < n; i++ {
		arr[i] = make([]string, n)
		for j := 0; j < n; j++ {
			arr[i][j] = "."
		}
	}
	// 从第1行开始,上层是满足条件
	dfs(arr, 0)
	return res
}

func dfs(arr [][]string, row int) {
	if len(arr) == row {
		temp := make([]string, 0)
		for i := 0; i < len(arr); i++ {
			str := ""
			for j := 0; j < len(arr[i]); j++ {
				str = str + arr[i][j]
			}
			temp = append(temp, str)
		}
		res = append(res, temp)
		return
	}
	// 每列尝试
	for col := 0; col < len(arr[0]); col++ {
		if valid(arr, row, col) == false {
			continue
		}
		arr[row][col] = "Q"
		dfs(arr, row+1)
		arr[row][col] = "."
	}
}

func valid(arr [][]string, row, col int) bool {
	n := len(arr)
	// 当前列判断(竖着)
	for row := 0; row < n; row++ {
		if arr[row][col] == "Q" {
			return false
		}
	}
	// 左上角
	for row, col := row-1, col-1; row >= 0 && col >= 0; row, col = row-1, col-1 {
		if arr[row][col] == "Q" {
			return false
		}
	}
	// 右上角
	for row, col := row-1, col+1; row >= 0 && col < n; row, col = row-1, col+1 {
		if arr[row][col] == "Q" {
			return false
		}
	}
	return true
}

# 2
var res [][]string
var rows, left, right []bool

func solveNQueens(n int) [][]string {
	res = make([][]string, 0)
	rows, left, right = make([]bool, n), make([]bool, 2*n-1), make([]bool, 2*n-1)
	// 初始化棋盘
	arr := make([][]string, n)
	for i := 0; i < n; i++ {
		arr[i] = make([]string, n)
		for j := 0; j < n; j++ {
			arr[i][j] = "."
		}
	}
	// 从第1行开始,上层是满足条件
	dfs(arr, 0)
	return res
}

func dfs(arr [][]string, row int) {
	n := len(arr)
	if len(arr) == row {
		temp := make([]string, 0)
		for i := 0; i < n; i++ {
			str := ""
			for j := 0; j < n; j++ {
				str = str + arr[i][j]
			}
			temp = append(temp, str)
		}
		res = append(res, temp)
		return
	}
	// 每列尝试
	for col := 0; col < n; col++ {
		if rows[col] == true || left[row-col+n-1] == true || right[row+col] == true {
			continue
		}
		rows[col], left[row-col+n-1], right[row+col] = true, true, true
		arr[row][col] = "Q"
		dfs(arr, row+1)
		arr[row][col] = "."
		rows[col], left[row-col+n-1], right[row+col] = false, false, false
	}
}

# 3
var res [][]string

func solveNQueens(n int) [][]string {
	res = make([][]string, 0)
	// 初始化棋盘
	arr := make([][]string, n)
	for i := 0; i < n; i++ {
		arr[i] = make([]string, n)
		for j := 0; j < n; j++ {
			arr[i][j] = "."
		}
	}
	// 从第1行开始,上层是满足条件
	dfs(arr, 0, 0, 0, 0)
	return res
}

func dfs(arr [][]string, row int, rows, left, right int) {
	n := len(arr)
	if len(arr) == row {
		temp := make([]string, 0)
		for i := 0; i < n; i++ {
			str := ""
			for j := 0; j < n; j++ {
				str = str + arr[i][j]
			}
			temp = append(temp, str)
		}
		res = append(res, temp)
		return
	}
	// 每列尝试
	for col := 0; col < n; col++ {
		a := uint(col)
		b := uint(row - col + n - 1)
		c := uint(row + col)
		if ((rows>>a)&1) != 0 || ((left>>b)&1) != 0 || ((right>>c)&1) != 0 {
			continue
		}
		arr[row][col] = "Q"
		dfs(arr, row+1, rows^(1<<a), left^(1<<b), right^(1<<c))
		arr[row][col] = "."
	}
}

52.N皇后II(3)

  • 题目

n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
上图为 8 皇后问题的一种解法。
给定一个整数 n,返回 n 皇后不同的解决方案的数量。
示例:输入: 4 输出: 2 解释: 4 皇后问题存在如下两个不同的解法。
[
 [".Q..",  // 解法 1
  "...Q",
  "Q...",
  "..Q."],

 ["..Q.",  // 解法 2
  "Q...",
  "...Q",
  ".Q.."]
]
提示:皇后,是国际象棋中的棋子,意味着国王的妻子。皇后只做一件事,那就是“吃子”。
    当她遇见可以吃的棋子时,就迅速冲上去吃掉棋子。当然,她横、竖、斜都可走一或 N-1 步,可进可退。
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 回溯 O(n^n) O(n^2)
02 回溯 O(n^n) O(n^2)
03 回溯-位运算 O(n^n) O(n)
var res int
var rows, left, right []bool

func totalNQueens(n int) int {
	res = 0
	rows, left, right = make([]bool, n), make([]bool, 2*n-1), make([]bool, 2*n-1)
	// 初始化棋盘
	arr := make([][]string, n)
	for i := 0; i < n; i++ {
		arr[i] = make([]string, n)
		for j := 0; j < n; j++ {
			arr[i][j] = "."
		}
	}
	// 从第1行开始,上层是满足条件
	dfs(arr, 0)
	return res
}

func dfs(arr [][]string, row int) {
	n := len(arr)
	if len(arr) == row {
		res++
		return
	}
	// 每列尝试
	for col := 0; col < n; col++ {
		if rows[col] == true || left[row-col+n-1] == true || right[row+col] == true {
			continue
		}
		rows[col], left[row-col+n-1], right[row+col] = true, true, true
		arr[row][col] = "Q"
		dfs(arr, row+1)
		arr[row][col] = "."
		rows[col], left[row-col+n-1], right[row+col] = false, false, false
	}
}

# 2
var res int

func totalNQueens(n int) int {
	res = 0
	// 初始化棋盘
	arr := make([][]string, n)
	for i := 0; i < n; i++ {
		arr[i] = make([]string, n)
		for j := 0; j < n; j++ {
			arr[i][j] = "."
		}
	}
	// 从第1行开始,上层是满足条件
	dfs(arr, 0)
	return res
}

func dfs(arr [][]string, row int) {
	if len(arr) == row {
		res++
		return
	}
	// 每列尝试
	for col := 0; col < len(arr[0]); col++ {
		if valid(arr, row, col) == false {
			continue
		}
		arr[row][col] = "Q"
		dfs(arr, row+1)
		arr[row][col] = "."
	}
}

func valid(arr [][]string, row, col int) bool {
	n := len(arr)
	// 当前列判断(竖着)
	for row := 0; row < n; row++ {
		if arr[row][col] == "Q" {
			return false
		}
	}
	// 左上角
	for row, col := row-1, col-1; row >= 0 && col >= 0; row, col = row-1, col-1 {
		if arr[row][col] == "Q" {
			return false
		}
	}
	// 右上角
	for row, col := row-1, col+1; row >= 0 && col < n; row, col = row-1, col+1 {
		if arr[row][col] == "Q" {
			return false
		}
	}
	return true
}

# 3
var res int

func totalNQueens(n int) int {
	res = 0
	// 从第1行开始,上层是满足条件
	dfs(0, n, 0, 0, 0)
	return res
}

func dfs(row, n int, rows, left, right int) {
	if n == row {
		res++
		return
	}
	// 每列尝试
	for col := 0; col < n; col++ {
		a := uint(col)
		b := uint(row - col + n - 1)
		c := uint(row + col)
		if ((rows>>a)&1) != 0 || ((left>>b)&1) != 0 || ((right>>c)&1) != 0 {
			continue
		}
		dfs(row+1, n, rows^(1<<a), left^(1<<b), right^(1<<c))
	}
}

57.插入区间(3)

  • 题目

给出一个无重叠的 ,按照区间起始端点排序的区间列表。
在列表中插入一个新的区间,你需要确保列表中的区间仍然有序且不重叠(如果有必要的话,可以合并区间)。
示例 1: 输入:intervals = [[1,3],[6,9]], newInterval = [2,5] 输出:[[1,5],[6,9]]
示例 2: 输入:intervals = [[1,2],[3,5],[6,7],[8,10],[12,16]], newInterval = [4,8]
输出:[[1,2],[3,10],[12,16]]
解释:这是因为新的区间 [4,8] 与 [3,5],[6,7],[8,10] 重叠。
注意:输入类型已在 2019 年 4 月 15 日更改。请重置为默认代码定义以获取新的方法签名。
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 遍历 O(n) O(n)
02 遍历 O(n) O(n)
03 排序遍历 O(nlog(n)) O(n)
func insert(intervals [][]int, newInterval []int) [][]int {
	res := make([][]int, 0)
	if len(intervals) == 0 {
		res = append(res, newInterval)
		return res
	}
	i := 0
	for ; i < len(intervals) && intervals[i][1] < newInterval[0]; i++ {
		res = append(res, intervals[i])
	}
	for ; i < len(intervals) && intervals[i][0] <= newInterval[1]; i++ {
		newInterval[0] = min(newInterval[0], intervals[i][0])
		newInterval[1] = max(newInterval[1], intervals[i][1])
	}
	res = append(res, newInterval)
	for ; i < len(intervals); i++ {
		res = append(res, intervals[i])
	}
	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 a
	}
	return b
}

# 2
func insert(intervals [][]int, newInterval []int) [][]int {
	if len(intervals) == 0 {
		return [][]int{newInterval}
	}
	i := 0
	for ; i < len(intervals) && intervals[i][1] < newInterval[0]; i++ {
	}
	left := i
	i = len(intervals) - 1
	for ; i >= 0 && intervals[i][0] > newInterval[1]; i-- {
	}
	right := i
	if left > right {
		return append(intervals[:left], append([][]int{newInterval}, intervals[left:]...)...)
	}
	newInterval[0] = min(newInterval[0], intervals[left][0])
	newInterval[1] = max(newInterval[1], intervals[right][1])
	return append(intervals[:left], append([][]int{newInterval}, intervals[right+1:]...)...)
}

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

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

# 3
func insert(intervals [][]int, newInterval []int) [][]int {
	res := make([][]int, 0)
	intervals = append(intervals, newInterval)
	sort.Slice(intervals, func(i, j int) bool {
		return intervals[i][0] < intervals[j][0]
	})
	res = append(res, intervals[0])
	for i := 1; i < len(intervals); i++ {
		arr := res[len(res)-1]
		if intervals[i][0] > arr[1] {
			res = append(res, intervals[i])
		} else if intervals[i][1] > arr[1] {
			res[len(res)-1][1] = intervals[i][1]
		}
	}
	return res
}

65.有效数字(1)

  • 题目

验证给定的字符串是否可以解释为十进制数字。
例如:
"0" => true
" 0.1 " => true
"abc" => false
"1 a" => false
"2e10" => true
" -90e3   " => true
" 1e" => false
"e3" => false
" 6e-1" => true
" 99e2.5 " => false
"53.5e93" => true
" --6 " => false
"-+3" => false
"95a54e53" => false
说明: 我们有意将问题陈述地比较模糊。在实现代码之前,你应当事先思考所有可能的情况。
这里给出一份可能存在于有效十进制数字中的字符列表:
    数字 0-9
    指数 - "e"
    正/负号 - "+"/"-"
    小数点 - "."
当然,在输入中,这些字符的上下文也很重要。
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 遍历 O(n) O(n)
func isNumber(s string) bool {
	s = strings.Trim(s, " ")
	if s == "" || len(s) == 0 || len(s) == 0 {
		return false
	}
	arr := []byte(s)
	i := 0
	numeric := scanInteger(&arr, &i)
	if i < len(arr) && arr[i] == '.' {
		i++
		numeric = scanUnsignedInteger(&arr, &i) || numeric
	}
	if i < len(arr) && (arr[i] == 'e' || arr[i] == 'E') {
		i++
		numeric = numeric && scanInteger(&arr, &i)
	}
	return numeric && len(arr) == i
}

func scanInteger(arr *[]byte, index *int) bool {
	if len(*arr) <= *index {
		return false
	}
	if (*arr)[*index] == '+' || (*arr)[*index] == '-' {
		*index++
	}
	return scanUnsignedInteger(arr, index)
}

func scanUnsignedInteger(arr *[]byte, index *int) bool {
	j := *index
	for *index < len(*arr) {
		if (*arr)[*index] < '0' || (*arr)[*index] > '9' {
			break
		}
		*index++
	}
	return j < *index
}

68.文本左右对齐(1)

  • 题目

给定一个单词数组和一个长度 maxWidth,重新排版单词,使其成为每行恰好有 maxWidth 个字符,
且左右两端对齐的文本。
你应该使用“贪心算法”来放置给定的单词;也就是说,尽可能多地往每行中放置单词。
必要时可用空格 ' ' 填充,使得每行恰好有 maxWidth 个字符。
要求尽可能均匀分配单词间的空格数量。
如果某一行单词间的空格不能均匀分配,则左侧放置的空格数要多于右侧的空格数。
文本的最后一行应为左对齐,且单词之间不插入额外的空格。
说明:单词是指由非空格字符组成的字符序列。
    每个单词的长度大于 0,小于等于 maxWidth。
    输入单词数组 words 至少包含一个单词。
示例:输入: words = ["This", "is", "an", "example", "of", "text", "justification."]
maxWidth = 16
输出:
[
   "This    is    an",
   "example  of text",
   "justification.  "
]
示例 2:输入: words = ["What","must","be","acknowledgment","shall","be"] maxWidth = 16
输出:
[
  "What   must   be",
  "acknowledgment  ",
  "shall be        "
]
解释: 注意最后一行的格式应为 "shall be    " 而不是 "shall     be",
     因为最后一行应为左对齐,而不是左右两端对齐。       
     第二行同样为左对齐,这是因为这行只包含一个单词。
示例 3:
输入:words = ["Science","is","what","we","understand","well","enough","to","explain",
         "to","a","computer.","Art","is","everything","else","we","do"]
maxWidth = 20
输出:
[
  "Science  is  what we",
  "understand      well",
  "enough to explain to",
  "a  computer.  Art is",
  "everything  else  we",
  "do                  "
]
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 遍历模拟 O(n) O(n)
func fullJustify(words []string, maxWidth int) []string {
	res := make([]string, 0)
	count := 0
	start := 0
	for i := 0; i < len(words); i++ {
		count = count + len(words[i])
		if count > maxWidth {
			temp := justify(words, start, i-1, maxWidth)
			res = append(res, temp)
			start = i
			if i == len(words)-1 {
				count = 0
				i--
			} else {
				count = len(words[i]) + 1
			}
		} else if i == len(words)-1 {
			temp := justify(words, start, i, maxWidth)
			res = append(res, temp)
		} else {
			count++
		}
	}
	return res
}

func justify(words []string, start, end int, maxWidth int) string {
	arr := make([]byte, maxWidth)
	for i := 0; i < len(arr); i++ {
		arr[i] = byte(' ')
	}
	index := 0
	// 文本的最后一行应为左对齐,且单词之间不插入额外的空格。
	if start == end || end == len(words)-1 {
		for i := start; i <= end; i++ {
			copy(arr[index:], words[i])
			index = index + len(words[i]) + 1
		}
	} else {
		// 要求尽可能均匀分配单词间的空格数量。
		// 如果某一行单词间的空格不能均匀分配,则左侧放置的空格数要多于右侧的空格数。
		count := end - start + 1
		left := maxWidth - count + 1
		for i := start; i <= end; i++ {
			left = left - len(words[i])
		}
		space := left / (count - 1) // 均分
		mod := left % (count - 1)   // 多的放左边
		for i := start; i <= end; i++ {
			copy(arr[index:], words[i])
			index = index + len(words[i]) + 1 + space
			if mod > 0 {
				index++
				mod--
			}
		}
	}
	return string(arr)
}

72.编辑距离(2)

  • 题目

给你两个单词 word1 和 word2,请你计算出将 word1 转换成 word2 所使用的最少操作数 。
你可以对一个单词进行如下三种操作:
    插入一个字符
    删除一个字符
    替换一个字符
示例 1:输入:word1 = "horse", word2 = "ros" 输出:3
解释:horse -> rorse (将 'h' 替换为 'r')
rorse -> rose (删除 'r')
rose -> ros (删除 'e')
示例 2:输入:word1 = "intention", word2 = "execution" 输出:5
解释: intention -> inention (删除 't')
inention -> enention (将 'i' 替换为 'e')
enention -> exention (将 'n' 替换为 'x')
exention -> exection (将 'n' 替换为 'c')
exection -> execution (插入 'u')
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 动态规划 O(n^2) O(n^2)
02 递归 O(n^2) O(n^2)
func minDistance(word1 string, word2 string) int {
	n1 := len(word1)
	n2 := len(word2)
	// dp[i][j]代表 word1的i位置转换成word2的j位置需要最少步数
	dp := make([][]int, n1+1)
	for i := 0; i < n1+1; i++ {
		dp[i] = make([]int, n2+1)
	}
	dp[0][0] = 0
	// 到word2[0]需要全部删除,有多少删除多少
	for i := 1; i <= n1; i++ {
		dp[i][0] = i
	}
	// 到word2[i]需要添加,有多少添加多少
	for i := 1; i <= n2; i++ {
		dp[0][i] = i
	}
	for i := 1; i <= n1; i++ {
		for j := 1; j <= n2; j++ {
			if word1[i-1] == word2[j-1] {
				dp[i][j] = dp[i-1][j-1] // 相同不需要操作
			} else {
				dp[i][j] = dp[i-1][j-1] + 1            // 替换
				dp[i][j] = min(dp[i][j], dp[i][j-1]+1) // 插入
				dp[i][j] = min(dp[i][j], dp[i-1][j]+1) // 删除
			}
		}
	}
	return dp[n1][n2]
}

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

# 2
var dp [][]int

func minDistance(word1 string, word2 string) int {
	dp = make([][]int, len(word1)+1)
	for i := 0; i < len(word1)+1; i++ {
		dp[i] = make([]int, len(word2)+1)
	}
	return helper(word1, word2, 0, 0)
}

func helper(word1, word2 string, i, j int) int {
	if dp[i][j] > 0 {
		return dp[i][j]
	}
	if i == len(word1) || j == len(word2) {
		return len(word1) - i + len(word2) - j
	}
	if word1[i] == word2[j] {
		return helper(word1, word2, i+1, j+1)
	}
	inserted := helper(word1, word2, i, j+1)
	deleted := helper(word1, word2, i+1, j)
	replaced := helper(word1, word2, i+1, j+1)
	dp[i][j] = min(inserted, min(deleted, replaced)) + 1
	return dp[i][j]
}

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

76.最小覆盖子串(2)

  • 题目

给你一个字符串 S、一个字符串 T 。
请你设计一种算法,可以在 O(n) 的时间复杂度内,从字符串 S 里面找出:包含 T 所有字符的最小子串。
示例:输入:S = "ADOBECODEBANC", T = "ABC" 输出:"BANC"
提示:如果 S 中不存这样的子串,则返回空字符串 ""。
    如果 S 中存在这样的子串,我们保证它是唯一的答案。
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 滑动窗口 O(n^2) O(n)
02 滑动窗口 O(n) O(n)
func minWindow(s string, t string) string {
	if len(s) < len(t) {
		return ""
	}
	window := make(map[byte]int)
	need := make(map[byte]int)
	for i := 0; i < len(t); i++ {
		need[t[i]]++
	}
	left, right := -1, -1
	minLength := math.MaxInt32
	for l, r := 0, 0; r < len(s); r++ {
		if r < len(s) && need[s[r]] > 0 {
			window[s[r]]++
		}
		// 找到,然后left往右移
		for check(need, window) == true && l <= r {
			if r-l+1 < minLength {
				minLength = r - l + 1
				left, right = l, r+1
			}
			if _, ok := need[s[l]]; ok {
				window[s[l]]--
			}
			l++
		}
	}
	if left == -1 {
		return ""
	}
	return s[left:right]
}

func check(need, window map[byte]int) bool {
	for k, v := range need {
		if window[k] < v {
			return false
		}
	}
	return true
}

# 2
func minWindow(s string, t string) string {
	if len(s) < len(t) {
		return ""
	}
	arr := make(map[byte]int)
	for i := 0; i < len(t); i++ {
		arr[t[i]]++
	}
	l, count := 0, 0
	res := ""
	minLength := math.MaxInt32
	for r := 0; r < len(s); r++ {
		arr[s[r]]--
		if arr[s[r]] >= 0 {
			count++
		}
		// left往右边移动
		for count == len(t) {
			if minLength > r-l+1 {
				minLength = r - l + 1
				res = s[l : r+1]
			}
			arr[s[l]]++
			if arr[s[l]] > 0 {
				count--
			}
			l++
		}
	}
	return res
}

84.柱状图中最大的矩形(5)

  • 题目

给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。
以上是柱状图的示例,其中每个柱子的宽度为 1,给定的高度为 [2,1,5,6,2,3]。
图中阴影部分为所能勾勒出的最大矩形面积,其面积为 10 个单位。
示例:输入: [2,1,5,6,2,3]输出: 10
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 暴力法 O(n^2) O(1)
02 暴力法 O(n^2) O(1)
03 单调栈 O(n) O(n)
04 单调栈 O(n) O(n)
05 单调栈 O(n) O(n)
func largestRectangleArea(heights []int) int {
	n := len(heights)
	res := 0
	for i := 0; i < n; i++ {
		height := heights[i]
		for j := i; j < n; j++ {
			width := j - i + 1
			height = min(height, heights[j])
			res = max(res, width*height)
		}
	}
	return res
}

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

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

# 2
func largestRectangleArea(heights []int) int {
	n := len(heights)
	res := 0
	for i := 0; i < n; i++ {
		height := heights[i]
		left, right := i, i
		for left > 0 && heights[left-1] >= height {
			left--
		}
		for right < n-1 && heights[right+1] >= height {
			right++
		}
		width := right - left + 1
		res = max(res, width*height)
	}
	return res
}

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

# 3
func largestRectangleArea(heights []int) int {
	n := len(heights)
	res := 0
	left := make([]int, n)
	right := make([]int, n)
	stack := make([]int, 0)
	for i := 0; i < n; i++ {
		for len(stack) > 0 && heights[stack[len(stack)-1]] >= heights[i] {
			stack = stack[:len(stack)-1]
		}
		if len(stack) == 0 {
			left[i] = -1
		} else {
			left[i] = stack[len(stack)-1]
		}
		stack = append(stack, i)
	}
	stack = make([]int, 0)
	for i := n - 1; i >= 0; i-- {
		for len(stack) > 0 && heights[stack[len(stack)-1]] >= heights[i] {
			stack = stack[:len(stack)-1]
		}
		if len(stack) == 0 {
			right[i] = n
		} else {
			right[i] = stack[len(stack)-1]
		}
		stack = append(stack, i)
	}
	for i := 0; i < n; i++ {
		res = max(res, heights[i]*(right[i]-left[i]-1))
	}
	return res
}

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

# 4
func largestRectangleArea(heights []int) int {
	n := len(heights)
	res := 0
	left := make([]int, n)
	right := make([]int, n)
	stack := make([]int, 0)
	for i := 0; i < n; i++ {
		right[i] = n
	}
	for i := 0; i < n; i++ {
		for len(stack) > 0 && heights[stack[len(stack)-1]] >= heights[i] {
			right[stack[len(stack)-1]] = i
			stack = stack[:len(stack)-1]
		}
		if len(stack) == 0 {
			left[i] = -1
		} else {
			left[i] = stack[len(stack)-1]
		}
		stack = append(stack, i)
	}

	for i := 0; i < n; i++ {
		res = max(res, heights[i]*(right[i]-left[i]-1))
	}
	return res
}

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

# 5
func largestRectangleArea(heights []int) int {
	heights = append([]int{0}, heights...)
	heights = append(heights, 0)
	n := len(heights)
	res := 0
	stack := make([]int, 0)
	for i := 0; i < n; i++ {
		// 递增栈
		for len(stack) > 0 && heights[stack[len(stack)-1]] > heights[i] {
			height := heights[stack[len(stack)-1]]
			stack = stack[:len(stack)-1]
			width := i - stack[len(stack)-1] - 1
			res = max(res, height*width)
		}
		stack = append(stack, i)
	}
	return res
}

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

85.最大矩形(2)

  • 题目

给定一个仅包含 0 和 1 的二维二进制矩阵,找出只包含 1 的最大矩形,并返回其面积。
示例:输入:
[
  ["1","0","1","0","0"],
  ["1","0","1","1","1"],
  ["1","1","1","1","1"],
  ["1","0","0","1","0"]
]
输出: 6
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 单调栈 O(n^2) O(n)
02 动态规划 O(n^2) O(n)
func maximalRectangle(matrix [][]byte) int {
	if len(matrix) == 0 || len(matrix[0]) == 0 {
		return 0
	}
	res := 0
	n, m := len(matrix), len(matrix[0])
	height := make([]int, m) // 高度
	for i := 0; i < n; i++ {
		for j := 0; j < m; j++ {
			if matrix[i][j] == '0' {
				height[j] = 0
			} else {
				height[j] = height[j] + 1
			}
		}
		res = max(res, getMaxArea(height))
	}
	return res
}

func getMaxArea(heights []int) int {
	heights = append([]int{0}, heights...)
	heights = append(heights, 0)
	n := len(heights)
	res := 0
	stack := make([]int, 0)
	for i := 0; i < n; i++ {
		// 递增栈
		for len(stack) > 0 && heights[stack[len(stack)-1]] > heights[i] {
			height := heights[stack[len(stack)-1]]
			stack = stack[:len(stack)-1]
			width := i - stack[len(stack)-1] - 1
			res = max(res, height*width)
		}
		stack = append(stack, i)
	}
	return res
}

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

# 2
func maximalRectangle(matrix [][]byte) int {
	if len(matrix) == 0 || len(matrix[0]) == 0 {
		return 0
	}
	res := 0
	n, m := len(matrix), len(matrix[0])
	left, right, height := make([]int, m), make([]int, m), make([]int, m)
	for i := 0; i < m; i++ {
		right[i] = m
	}
	for i := 0; i < n; i++ {
		curLeft, curRight := 0, m
		// 高度
		for j := 0; j < m; j++ {
			if matrix[i][j] == '1' {
				height[j]++
			} else {
				height[j] = 0
			}
		}
		// 左边
		for j := 0; j < m; j++ {
			if matrix[i][j] == '1' {
				left[j] = max(left[j], curLeft)
			} else {
				left[j] = 0
				curLeft = j + 1
			}
		}
		// 右边
		for j := m - 1; j >= 0; j-- {
			if matrix[i][j] == '1' {
				right[j] = min(right[j], curRight)
			} else {
				right[j] = m
				curRight = j
			}
		}
		for j := 0; j < m; j++ {
			res = max(res, height[j]*(right[j]-left[j]))
		}
	}
	return res
}

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

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

87.扰乱字符串(2)

  • 题目

给定一个字符串 s1,我们可以把它递归地分割成两个非空子字符串,从而将其表示为二叉树。
下图是字符串 s1 = "great" 的一种可能的表示形式。
    great
   /    \
  gr    eat
 / \    /  \
g   r  e   at
           / \
          a   t
在扰乱这个字符串的过程中,我们可以挑选任何一个非叶节点,然后交换它的两个子节点。
例如,如果我们挑选非叶节点 "gr" ,交换它的两个子节点,将会产生扰乱字符串 "rgeat" 。
    rgeat
   /    \
  rg    eat
 / \    /  \
r   g  e   at
           / \
          a   t
我们将 "rgeat” 称作 "great" 的一个扰乱字符串。
同样地,如果我们继续交换节点 "eat" 和 "at" 的子节点,将会产生另一个新的扰乱字符串 "rgtae" 。
    rgtae
   /    \
  rg    tae
 / \    /  \
r   g  ta  e
       / \
      t   a
我们将 "rgtae” 称作 "great" 的一个扰乱字符串。
给出两个长度相等的字符串 s1 和 s2,判断 s2 是否是 s1 的扰乱字符串。
示例 1:输入: s1 = "great", s2 = "rgeat" 输出: true
示例 2:输入: s1 = "abcde", s2 = "caebd" 输出: false
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 动态规划 O(n^4) O(n^3)
02 递归 O(5^n) O(n)
func isScramble(s1 string, s2 string) bool {
	n, m := len(s1), len(s2)
	if n != m {
		return false
	}
	// dp[i][j][l]:表示s1从i开始,s2从j开始长度为l的两个子字符串是扰乱
	dp := make([][][]bool, n+1)
	for i := 0; i <= n; i++ {
		dp[i] = make([][]bool, n+1)
		for j := 0; j <= n; j++ {
			dp[i][j] = make([]bool, n+1)
		}
	}
	// 单个字符
	for i := 0; i < n; i++ {
		for j := 0; j < n; j++ {
			dp[i][j][1] = s1[i] == s2[j]
		}
	}
	for k := 2; k <= n; k++ { // 枚举长度: 2-n
		for i := 0; i <= n-k; i++ { // s1起点
			for j := 0; j <= n-k; j++ { // s2起点
				dp[i][j][k] = false
				// 长度为w,分为两部分,其中最少是1
				for w := 1; w <= k-1; w++ {
					// 划分不交换:S1->T1, S2->T2
					// 划分交换: S1->T2, S2->T1
					if (dp[i][j][w] == true && dp[i+w][j+w][k-w] == true) ||
						(dp[i][j+k-w][w] == true && dp[i+w][j][k-w] == true) {
						dp[i][j][k] = true
					}
				}
			}
		}
	}
	return dp[0][0][n]
}

# 2
func isScramble(s1 string, s2 string) bool {
	return dfs([]byte(s1), []byte(s2))
}

func dfs(arr1, arr2 []byte) bool {
	if compare(arr1, arr2) == false {
		return false
	}
	if len(arr1) <= 2 {
		return (len(arr1) == 2 && ((arr1[0] == arr2[0] && arr1[1] == arr2[1]) ||
			(arr1[0] == arr2[1] && arr1[1] == arr2[0]))) ||
			(len(arr1) == 1 && arr1[0] == arr2[0])
	}
	for i := 1; i < len(arr1); i++ {
		leftA, rightA := arr1[:i], arr1[i:]
		leftB, rightB := arr2[:i], arr2[i:]
		LB, RB := arr2[len(arr1)-i:], arr2[:len(arr1)-i]
		if (dfs(leftA, leftB) && dfs(rightA, rightB)) || (dfs(leftA, LB) && dfs(rightA, RB)) {
			return true
		}
	}
	return false
}

func compare(arr1, arr2 []byte) bool {
	if len(arr1) != len(arr2) {
		return false
	}
	arrA := make([]byte, 26)
	arrB := make([]byte, 26)
	for i := 0; i < len(arr1); i++ {
		arrA[arr1[i]-'a']++
		arrB[arr2[i]-'a']++
	}
	for i := 0; i < len(arrA); i++ {
		if arrA[i] != arrB[i] {
			return false
		}
	}
	return true
}

97.交错字符串(3)

  • 题目

给定三个字符串 s1, s2, s3, 验证 s3 是否是由 s1 和 s2 交错组成的。
示例 1:输入:s1 = "aabcc", s2 = "dbbca", s3 = "aadbbcbcac" 输出:true
示例 2:输入:s1 = "aabcc", s2 = "dbbca", s3 = "aadbbbaccc" 输出:false
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 动态规划 O(n^2) O(n^2)
02 动态规划-一维 O(n^2) O(n)
03 递归 O(n) O(n)
func isInterleave(s1 string, s2 string, s3 string) bool {
	n, m, t := len(s1), len(s2), len(s3)
	if n+m != t {
		return false
	}
	// dp[i][j]表示s1的前i个元素和s2的前j个元素是否能交错组成s3的前i+j个元素
	dp := make([][]bool, n+1)
	for i := 0; i <= n; i++ {
		dp[i] = make([]bool, m+1)
	}
	dp[0][0] = true
	for i := 0; i <= n; i++ {
		for j := 0; j <= m; j++ {
			total := i + j - 1
			if i > 0 && dp[i-1][j] == true && s1[i-1] == s3[total] {
				dp[i][j] = true
			}
			if j > 0 && dp[i][j-1] == true && s2[j-1] == s3[total] {
				dp[i][j] = true
			}
		}
	}
	return dp[n][m]
}

# 2
func isInterleave(s1 string, s2 string, s3 string) bool {
	n, m, t := len(s1), len(s2), len(s3)
	if n+m != t {
		return false
	}
	// dp[j]表示s1的前i个元素和s2的前j个元素是否能交错组成s3的前i+j个元素
	dp := make([]bool, m+1)
	dp[0] = true
	for i := 0; i <= n; i++ {
		for j := 0; j <= m; j++ {
			total := i + j - 1
			if i > 0 {
				if dp[j] == true && s1[i-1] == s3[total] {
					dp[j] = true
				} else {
					dp[j] = false
				}
			}
			if j > 0 {
				if dp[j] == true || (dp[j-1] == true && s2[j-1] == s3[total]) {
					dp[j] = true
				} else {
					dp[j] = false
				}
			}
		}
	}
	return dp[m]
}

# 3
func isInterleave(s1 string, s2 string, s3 string) bool {
	if len(s1)+len(s2) != len(s3) {
		return false
	}
	return dfs(s1, s2, s3, 0, 0, 0)
}

func dfs(s1, s2, s3 string, i, j, k int) bool {
	if k == len(s3) && i == len(s1) && j == len(s2) {
		return true
	}
	if k >= len(s3) {
		return false
	}
	if i < len(s1) {
		if s1[i] == s3[k] {
			if dfs(s1, s2, s3, i+1, j, k+1) {
				return true
			}
		}
	}
	if j < len(s2) {
		if s2[j] == s3[k] {
			if dfs(s1, s2, s3, i, j+1, k+1) {
				return true
			}
		}
	}
	return false
}

99.恢复二叉搜索树(4)

  • 题目

二叉搜索树中的两个节点被错误地交换。
请在不改变其结构的情况下,恢复这棵树。
示例 1:输入: [1,3,null,null,2]
   1
  /
 3
  \
   2
输出: [3,1,null,null,2]
   3
  /
 1
  \
   2
示例 2:输入: [3,1,4,null,null,2]
  3
 / \
1   4
   /
  2
输出: [2,1,4,null,null,3]
  2
 / \
1   4
   /
  3
进阶:使用 O(n) 空间复杂度的解法很容易实现。你能想出一个只使用常数空间的解决方案吗?
  • 解题思路

No. 思路 时间复杂度 空间复杂度
01 递归 O(n) O(n)
02 递归 O(n) O(log(n))
03 迭代 O(n) O(n)
04 迭代 O(n) O(1)
var arr []*TreeNode

func recoverTree(root *TreeNode) {
	arr = make([]*TreeNode, 0)
	dfs(root)
	a, b := -1, -1
	for i := 0; i < len(arr)-1; i++ {
		if arr[i].Val > arr[i+1].Val {
			b = i + 1
			if a == -1 {
				a = i
			}
		}
	}
	arr[a].Val, arr[b].Val = arr[b].Val, arr[a].Val
}

func dfs(root *TreeNode) {
	if root == nil {
		return
	}
	dfs(root.Left)
	arr = append(arr, root)
	dfs(root.Right)
}

# 2
var prev, first, second *TreeNode

func recoverTree(root *TreeNode) {
	prev, first, second = nil, nil, nil
	dfs(root)
	first.Val, second.Val = second.Val, first.Val
}

func dfs(root *TreeNode) {
	if root == nil {
		return
	}
	dfs(root.Left)
	if prev != nil && prev.Val > root.Val {
		second = root
		if first == nil {
			first = prev
		} else {
			return
		}
	}
	prev = root
	dfs(root.Right)
}

# 3
func recoverTree(root *TreeNode) {
	var prev, first, second *TreeNode
	stack := make([]*TreeNode, 0)
	for len(stack) > 0 || root != nil {
		for root != nil {
			stack = append(stack, root)
			root = root.Left
		}
		root = stack[len(stack)-1]
		stack = stack[:len(stack)-1]
		if prev != nil && root.Val < prev.Val {
			second = root
			if first == nil {
				first = prev
			} else {
				break
			}
		}
		prev = root
		root = root.Right
	}
	first.Val, second.Val = second.Val, first.Val
}

# 4
func recoverTree(root *TreeNode) {
	var prev, temp, first, second *TreeNode
	for root != nil {
		temp = root.Left
		if temp != nil {
            // 当前root节点向左走一步,然后一直向右走至无法走为止
			for temp.Right != nil && temp.Right != root {
				temp = temp.Right
			}
			if temp.Right == nil {
				temp.Right = root
				root = root.Left
				continue
			} else {
				temp.Right = nil
			}
		}
		if prev != nil && prev.Val > root.Val {
			second = root
			if first == nil {
				first = prev
			}
		}
		prev = root
		root = root.Right
	}
	first.Val, second.Val = second.Val, first.Val
}