相交链表 相交链表
解题思路 首先计算两个链表的长度 len1
和len2
,对于较长的链表,其指针先向后移动 |len1-len2|
步,接着两个链表的指针同步向后移动 ,当两个指针相等时,说明到达了相交链表的第一个节点。
解题代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 func getIntersectionNode (headA, headB *ListNode) *ListNode { if headA == nil || headB == nil { return nil } len1, len2 := Length(headA), Length(headB) p, q := headA, headB if len1 > len2 { k := len1 - len2 p = MoveKStep(p, k) } else { k := len2 - len1 q = MoveKStep(q, k) } for p != nil { if p == q { return p } p = p.Next q = q.Next } return nil } func Length (head *ListNode) int { var length int p := head for p != nil { p = p.Next length++ } return length } func MoveKStep (p *ListNode, k int ) *ListNode { for k > 0 { p = p.Next k-- } return p }
合并两个有序数组 合并两个有序数组
解题思路 因为需要合并nums2
到nums1
,所以设立一个辅助数组 aux
,拷贝nums1
的所有值到aux
之中。接着利用归并 的思想,合并两个有序数组。
解题代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 func merge (nums1 []int , m int , nums2 []int , n int ) { aux := make ([]int , m) copy (aux, nums1) var i, j, k int for i < m && j < n { if aux[i] <= nums2[j] { nums1[k] = aux[i] i++ k++ } else { nums1[k] = nums2[j] j++ k++ } } for i < m { nums1[k] = aux[i] i++ k++ } for j < n { nums1[k] = nums2[j] j++ k++ } }
买卖股票的最佳时机 买卖股票的最佳时机
解题思路
暴力法,遍历出所有的可能性,时间复杂度为O(n^2)
动态规划 ,以minPrice
表示当前最小价格,dp[i]
表示前i天的最大利润 ,因为追求利润最大化,故dp[i] = max{ dp[i-1], prices-minPrice }
,时间复杂度降为O(n)
,空间复杂度为O(n)
。因为求dp[i]
只用到了dp[i-1]
,所以可以利用int
型变量记录,空间复杂度降为O(1)
解题代码
暴力法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 func maxProfit (prices []int ) int { n := len (prices) if n == 1 { return 0 } var profit int for i := 0 ; i < n-1 ; i++ { for j := i+1 ; j < n; j++ { if prices[j] - prices[i] > profit { profit = prices[j] - prices[i] } } } return profit }
动态规划
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 func maxProfit (prices []int ) int { n := len (prices) var dp int minPrice := prices[0 ] for i := 1 ; i < n; i++ { if prices[i] < minPrice { minPrice = prices[i] } if dp < prices[i] - minPrice { dp = prices[i] - minPrice } } return dp }
有效的括号 括号匹配
解题思路 利用栈来记录待匹配的左括号,从前向后遍历字符串,若遇到左括号则入栈,若遇到右括号,则栈顶元素出栈匹配右括号,若栈为空或者括号类型不匹配直接返回false
。当遍历完字符串后,若栈不为空,说明多出了左括号,返回false
;栈为空返回true
解题代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 func isValid (s string ) bool { n := len (s) stack := make ([]rune , n) top := -1 for _, val := range s { if val == '(' || val == '[' || val == '{' { top++ stack[top] = val } else { if top == -1 { return false } else if (val == ')' && stack[top] == '(' ) || (val == ']' && stack[top] == '[' ) || (val == '}' && stack[top] == '{' ) { top-- } else { return false } } } if top != -1 { return false } else { return true } }
二叉树的锯齿形层次遍历 二叉树的锯齿形层次遍历
解题思路 以二叉树的层序遍历为基础,将队列改为栈 ,来进行层序遍历。
当遍历第偶数层(以根节点为第0层)时,节点依次出栈遍历,并将各个节点的子树从左向右 入栈
当遍历奇数层时,节点依次出栈遍历,并将各个节点的子树从右向左 入栈
解题代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 func zigzagLevelOrder (root *TreeNode) [][]int { ret := [][]int {} if root == nil { return ret } q := []*TreeNode{root} for i := 0 ; len (q) > 0 ; i++ { p := []*TreeNode{} ret = append (ret, []int {}) for j := 0 ; j < len (q); j++ { cur := q[len (q)-j-1 ] ret[i] = append (ret[i], cur.Val) if i % 2 == 0 { if cur.Left != nil { p = append (p, cur.Left) } if cur.Right != nil { p = append (p, cur.Right) } } else { if cur.Right != nil { p = append (p, cur.Right) } if cur.Left != nil { p = append (p, cur.Left) } } } q = p } return ret }