leetcode(中等)

文章目录

  • 两数相加
  • 无重复字符的最长子串
  • 最长回文子串
  • 盛最多水的容器
  • 三数之和
  • 电话号码的字母组合
  • 括号生成
  • 下一个排序
  • 搜索旋转排序数组
  • 在排序数组中查找元素的第一个和最后一个位置
  • 组合总和
  • 旋转图像
  • 字母异位词分组
  • 跳跃游戏
  • 合并区间
  • 不同路径
  • 最小路径和
  • 颜色分类
  • 子集
  • 单词搜索
  • 不同的二叉搜索树
  • 验证二叉搜索树
  • 二叉树的层次遍历
  • 从前序与中序遍历序列构造二叉树
  • 二叉树展开为链表
  • 最长连续序列
  • 单词拆分
  • 环形链表Ⅱ
  • LRU缓存
  • 排序链表
  • 乘积最大子数组
  • 打家劫舍

两数相加

func addTwoNumbers(l1 *ListNode, l2 *ListNode) *ListNode {
	add := 0
	var cur *ListNode
	var head *ListNode
	x, y := 0, 0
	var num int
	for l1 != nil || l2 != nil || add != 0 {
		if l1 == nil {
			x = 0
		} else {
			x = l1.Val
			l1 = l1.Next
		}
		if l2 == nil {
			y = 0
		} else {
			y = l2.Val
			l2 = l2.Next
		}
		num = x + y + add
		add = num / 10
		if head == nil {
			cur = new(ListNode)
			cur.Val = num % 10
			head = cur
		} else {
			after := new(ListNode)
			after.Val = num % 10
			cur.Next = after
			cur = after
		}
	}
	return head
}

无重复字符的最长子串

解法1:用map做队列

func lengthOfLongestSubstring(s string) int {
	pos := make(map[int]int, 30)
	start := 0
	ans := 0
	for i, v := range s {
		num := int(v - 'a')
		if value, ok := pos[num]; ok {
			for k := range pos {
				if pos[k] <= value {
					delete(pos, k)
				}
			}
			start = value + 1
			pos[num] = i
		} else {
			pos[num] = i
			cur := i - start + 1
			if cur > ans {
				//fmt.Printf("%v %v\n", start, i)
				ans = cur
			}
		}
	}
	return ans
}

解法2:用string做队列

func lengthOfLongestSubstring(s string) int {
	str := ""
	ans := 0
	for _, v := range s {
		c := string(v)
		index := strings.Index(str, c)
		if index != -1 {
			str = str[index+1:] + c
		} else {
			str = str + c
		}
		l := len(str)
		if l > ans {
			ans = l
		}
	}
	return ans
}

最长回文子串

解法1:动态规划
时间复杂度O(n2
空间复杂度O(n2

func longestPalindrome(s string) string {
	n := len(s)
	dp := make([][]bool, n)
	for i := 0; i < n; i++ {
		cur := make([]bool, n)
		cur[i] = true
		dp[i] = cur
	}
	ans := 0
	str := string(s[0])
	//babad
	for i := 0; i < n; i++ {
		for j := 0; j < i; j++ {
			//fmt.Printf("i:%v j:%v vali:%v valj:%v dp:%v\n", i, j, s[i], s[j], dp[j+1][i-1])
			if s[i] == s[j] && (j+1 >= i-1 || dp[j+1][i-1] == true) {
				//fmt.Printf("i:%v j:%v vali:%v valj:%v\n", i, j, s[i], s[j])
				dp[j][i] = true
				if i-j+1 > ans {
					ans = i - j + 1
					str = s[j : i+1]
				}
			}
		}
	}
	return str
}

解法2:中心扩展

时间复杂度:O(n2
空间复杂度:O(1)


func longestPalindrome(s string) string {
	ans := ""
	maxl := 0
	for i := 0; i < len(s); i++ {
		s1 := center(s, i, i)
		s2 := center(s, i, i+1)
		s1_len, s2_len := len(s1), len(s2)
		if s1_len > s2_len && s1_len > maxl {
			maxl = s1_len
			ans = s1
		} else if s1_len < s2_len && s2_len > maxl {
			maxl = s2_len
			ans = s2
		}
	}
	return ans
}

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

盛最多水的容器

func maxArea(height []int) int {
	l, r := 0, len(height)-1
	ans := 0
	var cur int
	for l < r {
		if height[l] < height[r] {
			cur = height[l] * (r - l)
			l++
		} else {
			cur = height[r] * (r - l)
			r--
		}
		if cur > ans {
			ans = cur
		}
	}
	return ans
}

时间复杂度O(n)
空间复杂度O(1)

三数之和


func threeSum(nums []int) [][]int {
	n := len(nums)
	if n < 3 {
		return [][]int{}
	}
	ans := [][]int{}
	sort.Ints(nums)
	var sum int
	for i := 0; i < n; i++ {
		if i > 0 && nums[i] == nums[i-1] {
			continue
		}
		l, r := i+1, n-1
		for l < r {
			if l > i+1 && nums[l] == nums[l-1] {
				l++
				continue
			}
			if r < n-1 && nums[r] == nums[r+1] {
				r--
				continue
			}
			sum = nums[l] + nums[r] + nums[i]
			if sum == 0 {
				cur := []int{nums[l], nums[i], nums[r]}
				ans = append(ans, cur)
				l++
				r--
			} else if sum > 0 {
				r--
			} else {
				l++
			}
		}
	}

	return ans
}

时间复杂度O(n2
空间复杂度O(1)

电话号码的字母组合

func letterCombinations(digits string) []string {
	if digits == "" {
		return nil
	}
	f := make(map[uint8][]string, 8)
	f[2] = []string{"a", "b", "c"}
	f[3] = []string{"d", "e", "f"}
	f[4] = []string{"g", "h", "i"}
	f[5] = []string{"j", "k", "l"}
	f[6] = []string{"m", "n", "o"}
	f[7] = []string{"p", "q", "r", "s"}
	f[8] = []string{"t", "u", "v"}
	f[9] = []string{"w", "x", "y", "z"}
	ans := []string{}
	n := len(digits)
	var dfs func(index int, cur string)
	dfs = func(index int, cur string) {
		if index == n {
			ans = append(ans, cur)
			return
		}
		v := digits[index] - '0'
		for _, val := range f[v] {
			dfs(index+1, cur+val)
		}

	}
	dfs(0, "")
	return ans
}

时间复杂度O(3m+4n
空间复杂度O(n)

括号生成

func generateParenthesis(n int) []string {
	var dfs func(open, close int, cur string)
	ans := []string{}
	dfs = func(open, close int, cur string) {
		if len(cur) == 2*n {
			ans = append(ans, cur)
			return
		}
		if open < n {
			dfs(open+1, close, cur+"(")
		}
		if open > close {
			dfs(open, close+1, cur+")")
		}
	}
	dfs(0, 0, "")
	return ans
}

时间复杂度O(n)
空间复杂度O(n)

下一个排序

leetcode(中等)_第1张图片

如图所示,如果查找该数组的下一个全排序,我们需要从右往左找到第一个比右边小的点,然后跟右边仅大于该点的点进行交换。
leetcode(中等)_第2张图片
交换后,右边这个点的右边需要成为一个递增的序列就是我们所要的解
leetcode(中等)_第3张图片

func nextPermutation(nums []int) {
	n := len(nums)
	if n == 0 {
		return
	}
	var index = n - 1
	for i := n - 1; i >= 1; i-- {
		if nums[i-1] < nums[i] {
			index = i - 1
			break
		}
	}
	if index == n-1 {
		sort.Ints(nums)
		return
	}
	cur := nums[index]
	var index2 int
	for i := n - 1; i > index; i-- {
		if cur < nums[i] {
			index2 = i
			break
		}
	}
	nums[index], nums[index2] = nums[index2], nums[index]
	sort.Ints(nums[index+1:])
	return
}

时间复杂度O(nlog(n))
空间复杂度O(1)

搜索旋转排序数组

二分法
一定有一半的数组是单调的
如果nums[mid]>nums[0]时:

0~mid一定是单调递增的,这时如果nums[mid]target并且最小的nums[l]>target,一定是在[mid+1,r]

如果nums[mid]

mid+1~r一定是单调递增的,这时如果nums[mid]>target,一定是在[l,mid-1]区间内
如果nums[mid]
func search(nums []int, target int) int {
	l, r := 0, len(nums)-1
	for l < r {
		mid := (l + r) >> 1
		if nums[mid] == target {
			return mid
		}
		//fmt.Println(l, r, nums[mid])
		if nums[l] == target {
			return l
		}
		if nums[mid] < target {
			if nums[0] < nums[mid] || nums[r] >= target {
				l = mid + 1
			} else {
				r = mid
			}
		} else {
			if nums[0] > nums[mid] || nums[l] < target {
				r = mid
			} else {
				l = mid + 1
			}
		}
	}
	if nums[r] == target {
		return r
	}
	return -1
}

时间复杂度O(logn)
空间复杂度O(1)

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

func searchRange(nums []int, target int) []int {
	n := len(nums)
	if n == 0 {
		return []int{-1, -1}
	}
	start, end := 0, n-1
	var mid int
	ans := make([]int, 2)
	for start < end {
		mid = (start + end) >> 1
		if nums[mid] < target {
			start = mid + 1
		} else {
			end = mid
		}
	}
	if nums[start] == target {
		ans[0] = start
	} else {
		return []int{-1, -1}
	}
	end = n - 1
	for start < end-1 {
		mid = (start + end) >> 1
		if nums[mid] > target {
			end = mid - 1
		} else {
			start = mid
		}
	}
	if nums[end] == target {
		ans[1] = end
	} else {
		ans[1] = start
	}
	return ans
}

时间复杂度O(log(n))
空间复杂度O(1)

组合总和

func combinationSum(candidates []int, target int) [][]int {
	n := len(candidates)
	if n == 0 {
		return nil
	}
	ans := [][]int{}
	cur := []int{}
	var dfs func(sum int, index int)
	dfs = func(sum int, index int) {
		if sum > target || index >= n {
			return
		}
		if sum == target {
			tmp := make([]int, len(cur))
			copy(tmp, cur)
			ans = append(ans, tmp)
			return
		}
		dfs(sum, index+1)
		num := candidates[index]
		cur = append(cur, num)
		dfs(sum+num, index)
		cur = cur[:len(cur)-1]
	}
	dfs(0, 0)
	return ans
}

空间复杂度:O(target)

旋转图像

func rotate(matrix [][]int) {
	n := len(matrix)
	if n == 0 {
		return
	}
	var j int
	for i := 0; i < (n+1)/2; i++ {
		tmp := make([]int, n-2*i)
		copy(tmp, matrix[i][i:n-i])
		for j = i + 1; j < n-i; j++ {
			matrix[i][n-j-1] = matrix[j][i]
		}
		for j = i + 1; j < n-i; j++ {
			matrix[j][i] = matrix[n-i-1][j]
		}
		for j = i + 1; j < n-i; j++ {
			matrix[n-i-1][j] = matrix[n-j-1][n-i-1]
		}
		for j = 0; j < n-2*i; j++ {
			matrix[i+j][n-i-1] = tmp[j]
		}
	}
}

时间复杂度O(n2
空间复杂度O(n)

字母异位词分组

解1:hash表+排序

func groupAnagrams(strs []string) [][]string {
	n := len(strs)
	if n == 0 {
		return [][]string{strs}
	}
	cur := map[string][]string{}
	ans := [][]string{}
	for _, v := range strs {
		tmp := []byte(v)
		sort.Slice(tmp, func(i, j int) bool {
			return tmp[i] < tmp[j]
		})
		s := string(tmp)
		cur[s] = append(cur[s], v)
	}
	for _, v := range cur {
		ans = append(ans, v)
	}
	return ans
}

时间复杂度O(nklog(k))k是字符串的长度
空间复杂度O(nk)

解2:hash数组存字符串所有字母的个数集合

func groupAnagrams(strs []string) [][]string {
	n := len(strs)
	if n == 0 {
		return [][]string{strs}
	}
	cur := map[[26]int][]string{}
	ans := [][]string{}
	for _, v := range strs {
		cnt := [26]int{}
		for _, b := range v {
			cnt[b-'a']++
		}
		cur[cnt] = append(cur[cnt], v)
	}
	for _, v := range cur {
		ans = append(ans, v)
	}
	return ans
}

时间复杂度O(nk)k是字符串的最大长度
空间复杂度O(n
k)

跳跃游戏

解法1:标记数组

func canJump(nums []int) bool {
	is_ok := make([]bool, len(nums))
	is_ok[0] = true
	n := len(nums)
	if n == 0 {
		return true
	}
	var cur int
	for i, v := range nums {
		if !is_ok[i] {
			continue
		}
		for j := 1; j <= v; j++ {
			cur = i + j
			if cur > n-1 {
				break
			}
			is_ok[cur] = true
		}
	}
	return is_ok[n-1]
}

时间复杂度O(n*k) k是跳跃的步长
空间复杂度O(n)

解法2:扩展队列

func canJump(nums []int) bool {
	n := len(nums)
	if n <= 1 {
		return true
	}
	pos := make([]int, n)
	pos[0] = 0
	vis := make([]bool, n)
	l := 1
	var next int
	for l > 0 {
		cur := pos[l-1]
		//fmt.Println(cur)
		l--
		for i := 1; i <= nums[cur]; i++ {
			next = cur + i
			if next > n-1 || vis[next] {
				continue
			}
			if next == n-1 {
				return true
			}
			vis[next] = true
			pos[l] = next
			l++
		}
	}
	return false
}

时间复杂度O(n*k)
空间复杂度O (n)

解法3:记录最大位置
其实每次我们只需要遍历时记录能跳跃到的最大位置就可以,每次遍历时首先判断当前位置是不是超过了记录的最大位置,如果超过的话直接返回false就行了,因为最大位置到不了这的话更不可能达到最后一个点。如果遍历到的点位置小于记录的最大位置,则根据遍历到的位置再尝试更新最大位置。直到最大位置大于等于最终的位置返回true

func canJump(nums []int) bool {
	n := len(nums)
	if n <= 1 {
		return true
	}
	max_pos := 0
	for i, v := range nums {
		if i <= max_pos {
			if i+v > max_pos {
				max_pos = i + v
			}
		} else {
			return false
		}
		if max_pos >= n-1 {
			return true
		}
	}
	return false
}

时间复杂度O(n)
空间复杂度O(1)

合并区间

func merge(intervals [][]int) [][]int {
	n := len(intervals)
	if n <= 1 {
		return intervals
	}
	sort.Slice(intervals, func(i, j int) bool {
		if intervals[i][0] == intervals[j][0] {
			return intervals[i][1] < intervals[j][1]
		}
		return intervals[i][0] < intervals[j][0]
	})
	ans := [][]int{}
	start, end := intervals[0][0], intervals[0][1]
	for _, v := range intervals {
		if v[0] <= end && v[1] > end {
			end = v[1]
		} else if v[0] > end {
			ans = append(ans, []int{start, end})
			start = v[0]
			end = v[1]
		}
	}
	ans = append(ans, []int{start, end})
	return ans
}

时间复杂度:O(nlog(n))
空间复杂度:O(1)

不同路径

解1:dfs+剪枝

func uniquePaths(m int, n int) int {
	cnt := make([][]int, m)
	for i := 0; i < m; i++ {
		cur := make([]int, n)
		cnt[i] = cur
	}
	var dfs func(x, y int) int
	dfs = func(x, y int) int {
		if x >= m || y >= n {
			return 0
		}
		if cnt[x][y] != 0 {
			return cnt[x][y]
		}
		if x == m-1 && y == n-1 {
			return 1
		}
		cnt[x][y] = dfs(x+1, y) + dfs(x, y+1)
		return cnt[x][y]
	}
	return dfs(0, 0)
}

时间复杂度O(mn)
空间复杂度O(m
n)

解法2:组合排序
根据m和n我们可以知道向右和向下的总步数,分别是n-1和m-1,然后总步数是m+n-2,我们只需要在m+n-2当中选出n-1个向右的,剩余的为向下的,能选出的组合数就是结果

func uniquePaths(m, n int) int {
    return int(new(big.Int).Binomial(int64(m+n-2), int64(n-1)).Int64())
}

时间复杂度O(min(m,n))
空间复杂度O(1)

最小路径和

func min(x, y int) int {
	if x > y {
		return y
	}
	return x
}

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++ {
		cur := make([]int, m)
		dp[i] = cur
		if i != 0 {
			dp[i][0] = dp[i-1][0] + grid[i][0]
		} else {
			dp[0][0] = grid[0][0]
		}
	}
	for j := 1; j < m; j++ {
		dp[0][j] = dp[0][j-1] + grid[0][j]
	}
	for i := 1; i < n; i++ {
		for j := 1; j < m; j++ {
			dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + grid[i][j]
		}
	}
	//fmt.Println(dp)
	return dp[n-1][m-1]
}

时间复杂度O(mn)
空间复杂度O(mn)

滚动数组


func min(x, y int) int {
	if x > y {
		return y
	}
	return x
}

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]
	}
	tmp := make([]int, m)
	for i := 1; i < n; i++ {
		for j := 0; j < m; j++ {
			if j == 0 {
				tmp[j] = dp[j] + grid[i][j]
			} else {
				tmp[j] = min(dp[j], tmp[j-1]) + grid[i][j]
			}
		}
		copy(dp, tmp)
	}
	return dp[m-1]
}

时间复杂度O(mn)
空间复杂度O(m)可以进一步优化为O(min(m,n))

颜色分类

解法1:计数

func sortColors(nums []int) {
	n := len(nums)
	if n <= 1 {
		return
	}
	cnt0, cnt1, cnt2 := 0, 0, 0
	var i int
	for i = 0; i < n; i++ {
		if nums[i] == 1 {
			cnt1++
		} else if nums[i] == 0 {
			cnt0++
		} else {
			cnt2++
		}
	}
	i = 0
	for i < n {
		if i < cnt0 {
			nums[i] = 0
		} else if i < cnt0+cnt1 {
			nums[i] = 1
		} else {
			nums[i] = 2
		}
		i++
	}

}

解法2:双指针

func sortColors(nums []int) {
	n := len(nums)
	if n <= 1 {
		return
	}
	l, r := 0, 0
	for i, v := range nums {
		if v == 0 {
			nums[l], nums[i] = nums[i], nums[l]
			if nums[i] == 1 {
				nums[i], nums[r] = nums[r], nums[i]
			}
			l++
			r++
		} else if v == 1 {
			nums[r], nums[i] = nums[i], nums[r]
			r++
		}
	}

}

子集

func subsets(nums []int) [][]int {
	ans := [][]int{}
	n := len(nums)
	var dfs func(index int, cur []int)
	dfs = func(index int, cur []int) {
		if index == n {
			tmp := make([]int, len(cur))
			copy(tmp, cur)
			ans = append(ans, tmp)
			return
		}
		dfs(index+1, cur)
		dfs(index+1, append(cur, nums[index]))
	}
	cur := []int{}
	dfs(0, cur)
	return ans
}

时间复杂度O(n*2n
空间复杂度O(n)

单词搜索

解法1:回溯法

func exist(board [][]byte, word string) bool {
	lw := len(word)
	if lw == 0 {
		return true
	}
	n := len(board)
	if n == 0 {
		return true
	}
	m := len(board[0])
	vis := make([][]bool, n)
	for i := 0; i < n; i++ {
		cur := make([]bool, m)
		vis[i] = cur
	}
	var dfs func(x, y int, index int) bool
	dfs = func(x, y int, index int) bool {
		if index == lw {
			return true
		}
		if x >= n || y >= m || x < 0 || y < 0 || vis[x][y] {
			return false
		}
		if board[x][y] != word[index] {
			return false
		}
		vis[x][y] = true
		//fmt.Println(x, y, index)
		index++
		if dfs(x+1, y, index) || dfs(x-1, y, index) || dfs(x, y+1, index) || dfs(x, y-1, index) {
			return true
		}
		vis[x][y] = false
		return false
	}
	for i := 0; i < n; i++ {
		for j := 0; j < m; j++ {
			if board[i][j] == word[0] {
				for x := 0; x < n; x++ {
					for y := 0; y < m; y++ {
						vis[x][y] = false
					}
				}
				if dfs(i, j, 0) {
					return true
				}
			}
		}
	}
	return false
}

不同的二叉搜索树

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[j-1] * dp[i-j]
		}
	}
	return dp[n]
}

时间复杂度O(n2
空间复杂度O(n)

验证二叉搜索树

func isValidBST(root *TreeNode) bool {
	var dfs func(cur *TreeNode, min int, max int) bool
	dfs = func(cur *TreeNode, min int, max int) bool {
		if cur == nil {
			return true
		}
		if cur.Val <= min || cur.Val >= max {
			return false
		}
		return dfs(cur.Left, min, cur.Val) && dfs(cur.Right, cur.Val, max)
	}
	return dfs(root, math.MinInt64, math.MaxInt64)
}

时间复杂度O(n)
空间复杂度O(n)

二叉树的层次遍历

func levelOrder(root *TreeNode) [][]int {
	if root == nil {
		return nil
	}
	queue := []*TreeNode{root}
	ans := [][]int{}
	for i := 0; i < len(queue); i++ {
		cur := make([]*TreeNode, len(queue))
		copy(cur, queue)
		queue = nil
		tmp := []int{}
		for _, v := range cur {
			node := v
			if node.Left != nil {
				queue = append(queue, node.Left)
			}
			if node.Right != nil {
				queue = append(queue, node.Right)
			}
			tmp = append(tmp, node.Val)
		}
		ans = append(ans, tmp)
	}
	return ans
}

时间复杂度O(n)
空间复杂度O(n)

从前序与中序遍历序列构造二叉树

解法1:递归加遍历

func buildTree(preorder []int, inorder []int) *TreeNode {
	n := len(preorder)
	if len(inorder) != n {
		return nil
	}
	var dfs func(index, li, ri int) *TreeNode
	dfs = func(index, li, ri int) *TreeNode {
		if index >= n || li > ri {
			return nil
		}
		cur := preorder[index]
		next := li
		for next <= ri {
			if inorder[next] == cur {
				break
			}
			next++
		}
		node := new(TreeNode)
		node.Val = cur
		node.Left = dfs(index+1, li, next-1)
		node.Right = dfs(index+next-li+1, next+1, ri)
		return node
	}
	return dfs(0, 0, n-1)
}

时间复杂度O(n2
空间复杂度O(n)

解法2:哈希加遍历

func buildTree(preorder []int, inorder []int) *TreeNode {
	n := len(preorder)
	if len(inorder) != n {
		return nil
	}
	pos := make(map[int]int, n)
	for i, v := range inorder {
		pos[v] = i
	}
	var dfs func(index, li, ri int) *TreeNode
	dfs = func(index, li, ri int) *TreeNode {
		if index >= n || li > ri {
			return nil
		}
		cur := preorder[index]
		next := pos[cur]
		node := new(TreeNode)
		node.Val = cur
		node.Left = dfs(index+1, li, next-1)
		node.Right = dfs(index+next-li+1, next+1, ri)
		return node
	}
	return dfs(0, 0, n-1)
}

用哈希数组来代替遍历
时间复杂度O(n)
空间复杂度O(n)

二叉树展开为链表

解法1:递归

func flatten(root *TreeNode) {
	var dfs func(cur *TreeNode) *TreeNode
	if root == nil {
		return
	}
	dfs = func(cur *TreeNode) *TreeNode {
		if cur.Left == nil && cur.Right == nil {
			return cur
		}
		var node *TreeNode
		var node2 *TreeNode
		if cur.Left == nil {
			node2 = dfs(cur.Right)
			return node2
		} else if cur.Right == nil {
			node = dfs(cur.Left)
			cur.Right = cur.Left
			cur.Left = nil
			return node
		} else {
			node = dfs(cur.Left)
			node2 = dfs(cur.Right)
			node.Right = cur.Right
			cur.Right = cur.Left
			cur.Left = nil
			return node2
		}
	}
	dfs(root)
}

时间复杂度:O(n)
空间复杂度:O(n)

解法2:非递归遍历


func flatten(root *TreeNode) {
	if root == nil {
		return
	}
	stack := []*TreeNode{root}
	var pre *TreeNode
	for len(stack) > 0 {
		cur := stack[len(stack)-1]
		stack = stack[:len(stack)-1]
		if pre == nil {
			pre = cur
		} else {
			pre.Right = cur
			pre.Left = nil
			pre = cur
		}
		left, right := cur.Left, cur.Right
		if right != nil {
			stack = append(stack, right)
		}
		if left != nil {
			stack = append(stack, left)
		}
	}
}

时间复杂度:O(n)
空间复杂度:O(n)

解法3:寻找前驱节点

func flatten(root *TreeNode) {
	if root == nil {
		return
	}
	cur := root
	for cur != nil {
		if cur.Left != nil {
			next := cur.Left
			pre := next
			for pre.Right != nil {
				pre = pre.Right
			}
			pre.Right = cur.Right
			cur.Right = cur.Left
			cur.Left = nil
		}
		cur = cur.Right
	}
}

时间复杂度:O(n)
空间复杂度:O(1)

最长连续序列

func longestConsecutive(nums []int) int {
	n := len(nums)
	if n == 0 {
		return 0
	}
	vis := make(map[int]struct{}, n)
	for _, v := range nums {
		vis[v] = struct{}{}
	}
	max := 0
	var cnt int
	for index, _ := range vis {
		cnt = 1
		cur := index
		delete(vis, cur)
		for true {
			if _, ok := vis[cur+1]; ok {
				cur++
				cnt++
				delete(vis, cur)
			} else {
				break
			}
		}
		cur = index
		for true {
			if _, ok := vis[cur-1]; ok {
				cur--
				cnt++
				delete(vis, cur)
			} else {
				break
			}
		}
		if cnt > max {
			max = cnt
		}
	}
	return max
}

时间复杂度:O(n)
空间复杂度:O(n)

单词拆分

动态规划:
动态规划:dp[i]表示s[0:i+1]的字符串是否可以用wordDict拼接
dp[i]能够由wordDict拼接有两种情况:
1.s[0:i+1]可以直接从wordDict当中找到
2.存在j

func wordBreak(s string, wordDict []string) bool {
	n := len(s)
	if n == 0 {
		return true
	}
	dp := make([]bool, n)
	vis := make(map[string]bool, len(wordDict))
	for _, v := range wordDict {
		vis[v] = true
	}
	for i := 0; i < n; i++ {
		if vis[s[:i+1]] {
			dp[i] = true
			continue
		}
		for j := 0; j < i; j++ {
			if dp[j] && vis[s[j+1:i+1]] {
				dp[i] = true
			}
		}
	}
	return dp[n-1]
}

时间复杂度:O(m*n) m为字符串长度,n是数组长度
空间复杂度:O(max(m,n))

环形链表Ⅱ

快慢指针:设链表为a+b,a是环之前长度,b是环的长度。每次fast走两步,slow走一步。只要有环,两者一定会相遇。设相遇时slow走了s,则fast走了f,f=2s,f=s+nb。两者求得s=nb,f=2nb。然后再让s走a,就a+nb,就到了环的入口,怎么让s走a呢?只需要让fast再回到head,然后fast和slow每次走一步,两者相遇时就是环的入口的位置

func detectCycle(head *ListNode) *ListNode {
	fast, slow := head, head
	for true {
		if fast == nil || fast.Next == nil {
			return nil
		}
		fast = fast.Next.Next
		slow = slow.Next
		if fast == slow {
			break
		}
	}
	fast = head
	for fast != slow {
		fast = fast.Next
		slow = slow.Next
	}
	return fast
}

时间复杂度:O(n)
空间复杂度:O(1)

LRU缓存


type DLinkedNode struct {
	key, value int
	pre, next  *DLinkedNode
}

type LRUCache struct {
	size       int
	capacity   int
	cache      map[int]*DLinkedNode
	head, tail *DLinkedNode
}

func newNode(key, value int) *DLinkedNode {
	return &DLinkedNode{
		key:   key,
		value: value,
	}
}

func Constructor(capacity int) LRUCache {
	l := LRUCache{
		size:     0,
		capacity: capacity,
		cache:    make(map[int]*DLinkedNode, capacity),
		head:     newNode(0, 0),
		tail:     newNode(0, 0),
	}
	l.head.next = l.tail
	l.tail.pre = l.head
	return l
}

func (this *LRUCache) moveToHead(cur *DLinkedNode) {
	cur.pre.next = cur.next
	cur.next.pre = cur.pre
	cur.next = this.head.next
	this.head.next.pre = cur
	this.head.next = cur
	cur.pre = this.head
}

func (this *LRUCache) Get(key int) int {
	if _, ok := this.cache[key]; !ok {
		return -1
	}
	node := this.cache[key]
	if this.head.next == node {
		return node.value
	}
	this.moveToHead(node)
	return node.value
}

func (this *LRUCache) Put(key int, value int) {
	if _, ok := this.cache[key]; ok {
		node := this.cache[key]
		node.value = value
		this.moveToHead(node)
		return
	}
	if this.size < this.capacity {
		node := new(DLinkedNode)
		node.key = key
		node.value = value
		node.next = this.head.next
		this.head.next.pre = node
		this.head.next = node
		node.pre = this.head
		this.cache[key] = node
		this.size++
	} else {
		tail := this.tail.pre
		delete(this.cache, tail.key)
		tail.key = key
		tail.value = value
		this.cache[key] = tail
		this.moveToHead(tail)
	}
}

采用带首尾指针的双循环链表
时间复杂度O(1)
空间复杂度O(n)

排序链表

func sortList(head *ListNode) *ListNode {
	n := 0
	cur := head
	for cur != nil {
		n++
		cur = cur.Next
	}
	nodeIndex := make(map[int]*ListNode, n)
	cur = head
	for i := 0; i < n; i++ {
		nodeIndex[i] = cur
		cur = cur.Next
	}
	var mergeSort func(l int, r int) *ListNode
	mergeSort = func(l int, r int) *ListNode {
		if l == r-1 {
			nodeIndex[l].Next = nil
			return nodeIndex[l]
		}
		mid := (l + r) >> 1
		lList := mergeSort(l, mid)
		rList := mergeSort(mid, r)
		var tail *ListNode
		var head *ListNode
		for lList != nil || rList != nil {
			if rList == nil || (lList != nil && lList.Val <= rList.Val) {
				if tail == nil {
					tail = lList
					head = tail
				} else {
					tail.Next = lList
					tail = lList
				}
				lList = lList.Next
			} else if lList == nil || (rList != nil && rList.Val <= lList.Val) {
				if tail == nil {
					tail = rList
					head = tail
				} else {
					tail.Next = rList
					tail = rList
				}
				rList = rList.Next
			}
			tail.Next = nil
		}
		return head
	}
	return mergeSort(0, n)
}

时间复杂度:O(n*log(n))
空间复杂度:O(n)

乘积最大子数组

func maxProduct(nums []int) int {
	n := len(nums)
	if n == 0 {
		return 0
	}
	maxF, minF, ans := nums[0], nums[0], nums[0]
	for i := 1; i < n; i++ {
		mx, mn := maxF, minF
		maxF = max(mx*nums[i], max(nums[i], mn*nums[i]))
		minF = min(mn*nums[i], min(nums[i], mx*nums[i]))
		ans = max(ans, maxF)
	}
	return ans
}

func max(x, y int) int {
	if x > y {
		return x
	}
	return y
}

func min(x, y int) int {
	if x < y {
		return x
	}
	return y
}

时间复杂度:O(n)
空间复杂度:O(1)

打家劫舍

func rob(nums []int) int {
	n := len(nums)
	if n == 0 {
		return 0
	} else if n == 1 {
		return nums[0]
	}
	dp := make([]int, n)
	dp[0] = nums[0]
	dp[1] = max(nums[0], nums[1])
	for i := 2; i < n; i++ {
		dp[i] = max(dp[i-1], dp[i-2]+nums[i])
	}
	//for i := 0; i < n; i++ {
	//	fmt.Println(i, dp[i])
	//}
	return dp[n-1]
}

func max(x, y int) int {
	if x > y {
		return x
	}
	return y
}

时间复杂度:O(n)
空间复杂度:O(n)

用变量代替数组

func rob(nums []int) int {
	n := len(nums)
	if n == 0 {
		return 0
	} else if n == 1 {
		return nums[0]
	}
	min0 := nums[0]
	min1 := max(nums[0], nums[1])
	for i := 2; i < n; i++ {
		min1, min0 = max(min1, min0+nums[i]), min1

	}
	//for i := 0; i < n; i++ {
	//	fmt.Println(i, dp[i])
	//}
	return min1
}

func max(x, y int) int {
	if x > y {
		return x
	}
	return y
}

时间复杂度:O(n)
空间复杂度:O(1)

你可能感兴趣的:(go语言,leetcode,链表,算法)