求根节点到叶节点数字之和 求根节点到叶节点数字之和
解题思路 在二叉树的后序遍历算法中,访问一个节点时,栈中保存的是其所有的祖先 。可以根据二叉树的后序遍历算法 ,当访问到叶子节点时 ,栈中保存的就是从根节点到叶子节点的所有数字,将栈中节点转换为数字 ,加入到sum
中。后序遍历结束后,即可得到从根节点到叶节点生成的所有数字之和sum
解题代码 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 func sumNumbers (root *TreeNode) int { stack := make ([]*TreeNode, 0 ) cur := root var pre *TreeNode var sum int for len (stack) >0 || cur != nil { for cur != nil { stack = append (stack, cur) cur = cur.Left } if len (stack) > 0 { cur = stack[len (stack)-1 ] if cur.Right == nil || pre == cur.Right { if cur.Left == nil && cur.Right == nil { sum = sum + stackToInt(stack) } pre = cur stack = stack[:len (stack)-1 ] cur = nil } else { cur = cur.Right } } } return sum } func stackToInt (stack []*TreeNode) int { var res int for i := 0 ; i < len (stack); i++ { res = res*10 + stack[i].Val } return res }
从前序与中序遍历序列构造二叉树 从前序与中序遍历序列构造二叉树
解题思路 对于任意一颗树而言,前序遍历的形式 总是[ 根节点, [左子树的前序遍历结果], [右子树的前序遍历结果] ]
即根节点总是前序遍历中的第一个节点 。而中序遍历的形式 总是[ [左子树的中序遍历结果], 根节点, [右子树的中序遍历结果] ]
,左右子树分别在根节点的两侧 。
根据前序遍历结果的第一个节点 ,即可定位到中序遍历序列 中。由此根节点将中序遍历结果分割为左右子树的中序遍历序列 ,根据左右子树中序遍历序列的节点数目,就可以知道左右子树的节点数 ,由此可以将前序遍历序列分割为左子树和右子树的前序遍历结果 。递归构造左右子树即可构造出完整的二叉树。
解题代码 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 func buildTree (preorder []int , inorder []int ) *TreeNode { if len (preorder) > 0 { root := &TreeNode{} root.Val = preorder[0 ] var inorderRootIndex int for i := 0 ; i < len (inorder); i++ { if inorder[i] == root.Val { inorderRootIndex = i break } } inorderLeft := inorder[:inorderRootIndex] inorderRight := inorder[inorderRootIndex+1 :] preorderLeft := preorder[1 :1 +len (inorderLeft)] preorderRight := preorder[1 +len (inorderLeft):] root.Left = buildTree(preorderLeft, inorderLeft) root.Right = buildTree(preorderRight, inorderRight) return root } else { return nil } }
排序链表 排序链表
对链表进行插入排序
解题思路
对链表进行插入排序 ,时间复杂度高,达O(n^2)
对链表进行归并排序
自顶向下 的归并排序
利用快慢指针 找到链表的中间节点,以中间节点为界,将链表拆分成两个链表
分别对两个链表进行归并排序
将两个排序后的链表合并
自底向上 的归并排序
用subLength
表示每次排序的子表长度,初始时subLength = 1
每次将排序链表分成若干个长度为subLength
的子表进行合并
每次将整个链表都合并一趟过后,将subLength
乘以2倍,直到有序子链表的长度大于或等于链表长度
解题代码
插入排序
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 func insertionSortList (head *ListNode) *ListNode { if head == nil || head.Next == nil { return head } newHead := &ListNode{} newHead.Next = head cur, last := head.Next, head for cur != nil { p := newHead for p.Next != cur && p.Next.Val < cur.Val { p = p.Next } last.Next = cur.Next cur.Next = p.Next p.Next = cur if last.Next == cur { last = last.Next } cur = last.Next } return newHead.Next }
自顶向下的归并排序
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 55 56 57 58 59 60 61 62 63 64 65 66 67 func sortList (head *ListNode) *ListNode { return mergeSort(head, nil ) } func mergeSort (head, tail *ListNode) *ListNode { if head == nil { return head } if head.Next == tail { head.Next = nil return head } low, fast := head, head for fast.Next != tail { low = low.Next fast = fast.Next if fast.Next != tail { fast = fast.Next } } mid := low l1 := mergeSort(head, mid) l2 := mergeSort(mid, tail) return merge(l1, l2) } func merge (l1, l2 *ListNode) *ListNode { newHead := &ListNode{} rear := newHead p, q := l1, l2 for p != nil && q != nil { if p.Val <= q.Val { rear.Next = p rear = rear.Next p = p.Next rear.Next = nil } else { rear.Next = q rear = rear.Next q = q.Next rear.Next = nil } } if p != nil { rear.Next = p } if q != nil { rear.Next = q } return newHead.Next }
自底向上的归并排序
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 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 func sortList (head *ListNode) *ListNode { length := length(head) newHead := &ListNode{ Next: head } for subLength := 1 ; subLength < length; subLength *= 2 { pre, cur := newHead, newHead.Next for cur != nil { head1 := cur for i := 1 ; i < subLength && cur.Next != nil ; i++ { cur = cur.Next } head2 := cur.Next cur.Next = nil cur = head2 for i := 1 ; i < subLength && cur != nil && cur.Next != nil ; i++ { cur = cur.Next } var next * ListNode if cur != nil { next = cur.Next cur.Next = nil } pre.Next = merge(head1, head2) for pre.Next != nil { pre = pre.Next } cur = next } } return newHead.Next } func merge (l1, l2 *ListNode) *ListNode { newHead := &ListNode{} rear := newHead p, q := l1, l2 for p != nil && q != nil { if p.Val <= q.Val { rear.Next = p rear = rear.Next p = p.Next rear.Next = nil } else { rear.Next = q rear = rear.Next q = q.Next rear.Next = nil } } if p != nil { rear.Next = p } if q != nil { rear.Next = q } return newHead.Next } func length (head *ListNode) int { var len int p := head for p != nil { len ++ p = p.Next } return len }
字符串转换整数 字符串转换整数 (atoi)
解题思路 手动完成字符串转换整数,依次进行以下步骤:
丢弃无用的前导空格
记录符号位sign
:sign = 1
时,为正数;sign = -1
时,为负数
将字符串转换为整数:从前向后读取,碰到第一个非数字时停止
检测是否上溢出,若上溢出,则返回math.MaxInt32
检测是否下溢出,若下溢出,则返回math.MinInt32
res = res*10 + sign*int(s[i]-'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 myAtoi (s string ) int { s = ltrim(s) if len (s) == 0 { return 0 } sign := 1 if s[0 ] == '+' || s[0 ] == '-' { if s[0 ] == '-' { sign = -1 } s = s[1 :] } var res int for i := 0 ; i < len (s) && (s[i] >= '0' && s[i] <= '9' ) ; i++ { if sign == 1 && (res > math.MaxInt32/10 || (res == math.MaxInt32/10 && int (s[i]-'0' ) > math.MaxInt32%10 )) { return math.MaxInt32 } if sign == -1 && (res < math.MinInt32/10 || (res == math.MinInt32/10 && int (s[i]-'0' ) > (-math.MinInt32)%10 )) { return math.MinInt32 } res = res*10 + sign*int (s[i]-'0' ) } return res } func ltrim (s string ) string { var spaceNum int for i := 0 ; i < len (s); i++ { if s[i] != ' ' { break } spaceNum++ } return s[spaceNum:] }
最长公共子序列 最长公共子序列
解题思路 利用动态规划 的思想。设dp[i][j]
表示,text1
从第1
个字符到第i
个字符,text2
从第1
个字符到第j
个字符的最长公共子序列。
初始化:可以将第0
个字符看作是空串 ,所以dp[i][0]
和dp[0][j]
被初始化为0
状态转移方程:
若text1[i] == text2[j]
,说明两个子字符串的最后一位相等,则dp[i][j] = dp[i-1][j-1]+1
若text1[i] != text2[j]
,说明两个子字符串的最后一位不相等,则dp[i][j] = max(dp[i-1][j], dp[i][j-1])
解题代码 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 func longestCommonSubsequence (text1 string , text2 string ) int { len1 := len (text1) len2 := len (text2) if len1 == 0 || len2 == 0 { return 0 } dp := make ([][]int , len1+1 ) for i := 0 ; i <= len1; i++ { dp[i] = make ([]int , len2+1 ) } for i := 1 ; i <= len1; i++ { for j := 1 ; j <= len2; j++ { if text1[i-1 ] == text2[j-1 ] { dp[i][j] = dp[i-1 ][j-1 ] + 1 } else { dp[i][j] = max(dp[i-1 ][j], dp[i][j-1 ]) } } } return dp[len1][len2] } func max (n1, n2 int ) int { if n1 > n2 { return n1 } else { return n2 } }