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)
如图所示,如果查找该数组的下一个全排序,我们需要从右往左找到第一个比右边小的点,然后跟右边仅大于该点的点进行交换。
交换后,右边这个点的右边需要成为一个递增的序列就是我们所要的解
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(nk)
跳跃游戏
解法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(mn)
解法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,链表,算法)