Main purpose of this chapter
It mainly focuses on high-quality code, completeness, standardization and robustness.
The writing of test cases is usually done hastily in order to complete the unit test coverage. After studying this chapter, we can find that our previous test cases are very poor in practicability. There are only normal cases, and there is only one in many cases. After that, I also follow the use cases from three aspects: 1. Functional test, 2. Negative test, and 3. Boundary test. Negative test can be understood as error test and abnormal test.
Officially start Chapter 3
Interview question 11: integer power of value
leetcode-cn.com/problems/shu-zhi-d...
According to the meaning of the topic, it is easy to write the basic logic code.
func myPow(x float64, n int) float64 { var result = 1.0 if n < 0 { x = 1 / x n = -n } for i := 0; i < n; i++ { result *= x } return result }
Unfortunately, the timeout will be prompted, which is very embarrassing. So I read the logic of the original text and implemented it again. The logic is as follows:
Fast power algorithm
Algorithm flow:
When x = 0: directly return 0 (avoid error reporting in subsequent x = 1 / x operations).
Initialize res = 1
When n < 0: convert the problem to the range of n ≥ 0, that is, execute x = 1/x, n = - n;
Loop calculation: jump out when n = 0;
When n & 1 = = 1: multiply the current x into res (i.e. res *= x);
Execute x = x^2 (i.e. x *= x)
Perform n shift right one bit (i.e. n > > = 1).
Return res
func myPow(x float64, n int) float64 { var result = 1.0 if n < 0 { x = 1 / x n = -n } for ; n > 0; { if n&1 == 1 { //I also learned a bit operation, which is equivalent to n% 2 = = 1 result *= x } x *= x n >>= 1 // Halve the index } return result }
Interview question 12: print 1 to the maximum n digits
leetcode-cn.com/problems/da-yin-co...
Although it can pass leetcode, it is not in line with the purpose of making questions in the book, because we should consider the case of large numbers. The idea given in the book is to convert it into a string for output
func printNumbers(n int) []int { res := make([]int,0) var count = 1 for i := 1; i < n; i++ { count *= 10 } for i := 0; i < count; i++ { res = append(res,i) } return res }
This does not include large numbers, which is not the original intention of the book. It is revised as follows:
The integrity of the code is investigated. The return should be [] string instead of [] int. depending on the specific code, there is no way to verify it in leetcode. You can only print the log yourself.
func printNumbers(n int) []string { if n <= 0 { return nil } res := make([]int, 0) result := make([]string, 0) number := make([]int, n) for !increment(number) { for i := 0; i < len(number); i++ { res = append(res, number[i]) } } //The array is divided into n bits and is an array temp := make([]int, 0) for i := 0; i < len(res); i++ { temp = append(temp, res[i]) if (i+1)%n == 0 { // The remainder of 3 is 0. The description is an integral multiple of n result = append(result, getString(temp)) temp = make([]int, 0) } } return result } func getString(number []int) string { var res string isBegin := false for i := 0; i < len(number); i++ { if number[i] != 0 { isBegin = true } if isBegin { res += fmt.Sprintf("%d", number[i]) } } return res } func increment(number []int) bool { var isOverFlow = false //Overflow end var nTakeOver = 0 // carry var nLength = len(number) for i := nLength - 1; i >= 0; i-- { nSum := number[i] + nTakeOver if nLength-1 == i { nSum++ } if nSum >= 10 { if i == 0 { isOverFlow = true } else { nSum -= 10 nTakeOver = 1 number[i] = nSum } } else { number[i] = nSum break } } return isOverFlow }
Interview question 13: delete linked list nodes at O(1) time
leetcode-cn.com/problems/shan-chu-...
leetcode requires less time complexity than books
// Regardless of O (1), traversal is the most direct func deleteNode(head *ListNode, val int){ if head == nil { return } for head.Next != nil { if head.Next.Val == val { head.Next = head.Next.Next } head = head.Next } }
The linked list needs false head, new linked list, double pointer and other aids. At present, it is the best example of using false head. It is different from that in the book. Ha, the deletion in the textbook is over and there is no need to return. The force buckle is to return to the head node after deletion
func deleteNode(head *ListNode, val int) *ListNode { //for head.Next != nil { // if val == head.Next.Val { // head = head.Next.Next / / delete the node. This is the end. // } //} dummy := &ListNode{}// Generate a new linked list tail := dummy for head != nil { if head.Val != val { //Add to new linked list tail.Next = head tail = head } head = head.Next } tail.Next = nil //Set tail to empty return dummy.Next }
In the above example, the space complexity is O(n). If it wants to be 1, it can only be passed according to the parameters in the textbook. Otherwise, it cannot be realized
func deleteNode(head *ListNode, deleteNode *ListNode) { if head == nil || deleteNode == nil { return } if deleteNode.Next != nil {//Not a tail node //Delete the next value of the node, replace the node to be deleted, and then delete the next node, which is equivalent to deleting the current node deleteNode.Val = deleteNode.Next.Val deleteNode.Next = deleteNode.Next.Next }else if head == deleteNode {//The head node is deleted, and there is only one node head = nil }else{ // For multiple nodes, the tail node is deleted. Don't the first if condition include it? for head.Next != deleteNode { head = head.Next } head.Next = nil } }
Interview question 14: adjust the array order so that odd numbers precede even numbers
leetcode-cn.com/problems/diao-zhen...
Idea: two pointers, one pointing to the head and the other pointing to the tail. Both sides move to the middle at the same time. If the value of the head pointer is even and the tail pointer is odd, it will be exchanged
Generality: change the judgment condition to function to judge. Separate num [left] & 1 = = 1 and num [right] & 1 = = 0 and replace them with functions. It's very simple to add them by yourself.
func exchange(nums []int) []int { if len(nums) == 0 { return nil } var left = 0 var right = len(nums) - 1 for left < right { for left < right && nums[left]&1 == 1 { //Odd, shift right, left left++ } for left < right && nums[right]&1 == 0 { //Even, shift left right right-- } if left < right { //exchange nums[left], nums[right] = nums[right], nums[left] } } return nums }
Interview question 15: the penultimate node in the lin k ed list
leetcode-cn.com/problems/lian-biao...
Idea: two pointers, one pointing to the head and the other taking k steps first, referred to as fast and slow pointer for short
func getKthFromEnd(head *ListNode, k int) *ListNode { if head != nil { return nil } var first = head var second = head for i := 0; i < k; i++ { second = second.Next }else{//k is longer than the length of the entire linked list. Return to nil directly. If you don't want this step, you can still pass, and the robustness will become worse return nil } for second != nil { first = first.Next second = second.Next } return first }
Interview question 16: reverse linked list
leetcode-cn.com/problems/UHnkqh/
For this problem, if there is no limit to return the header node and only output, the implementation methods are N kinds, and the array is also possible. However, the requirement here is to return the inverted head node, so auxiliary means are required.
//You need to save the node to prevent it from being found after disconnection func reverseList(head *ListNode) *ListNode { var prevHead *ListNode //Save the previous node traversed var currentNode = head //Save the current node traversed for currentNode != nil { nextNode := currentNode.Next currentNode.Next = prevHead prevHead = currentNode currentNode = nextNode } return prevHead }
According to the practice in the textbook, I copied the code. However, I feel that there is a little problem with this code, but I don't know where the problem is. I hope you can point out what you know and correct it. Thank you very much.
func reverseList(head *ListNode) *ListNode { var reversedHead *ListNode //Inverted head node var prev *ListNode var node = head for node != nil { next := node.Next if next == nil { reversedHead = node } node.Next = prev prev = node node = next } return reversedHead }
Interview question 17: merge two sorted linked lists
leetcode-cn.com/problems/he-bing-l...
It also uses the false head of the linked list and the new linked list as an auxiliary
func mergeTwoLists(l1 *ListNode, l2 *ListNode) *ListNode { dummy := &ListNode{} tail := dummy for l1 != nil && l2 != nil { if l1.Val < l2.Val { tail.Next = l1 l1 = l1.Next } else { tail.Next = l2 l2 = l2.Next } tail = tail.Next } if l1 != nil {// If l1 there is, splice directly to the back tail.Next = l1 tail = tail.Next l1 = l1.Next } if l2 != nil {//If l2 there are any, directly splice the back tail.Next = l2 tail = tail.Next l2 = l2.Next } return dummy.Next }
Interview question 18: substructure of tree
leetcode-cn.com/problems/shu-de-zi...
Input two binary trees a and B to judge whether B is the substructure of A. (the contract empty tree is not a substructure of any tree)
Mainly related to trees, there is no simple level. Of course, there is no simple level related to recursion. Not familiar with recursion and tree, this problem needs some time to understand.
func isSubStructure(A *TreeNode, B *TreeNode) bool { var result = false if A != nil && B != nil { //First compare the root node, and then compare the left and right subtree nodes if A.Val == B.Val { //If the root node is satisfied, it is judged that it is not a substructure result = isStructure(A,B) //Without recursion, it can also be written as the judgment of left and right subtrees } //The left subtree of the comparison is the root node and starts to traverse the comparison if !result { result = isSubStructure(A.Left,B) } //Compare the right subtree as the root node and start traversing the comparison if !result { result = isSubStructure(A.Right,B) } } return result } func isStructure(a *TreeNode, b *TreeNode) bool { if b == nil {//Description tree B has been matched (beyond the leaf node), so it returns true return true } if a == nil {//It indicates that the leaf node of tree A has been crossed, that is, the matching fails, and false is returned return false } if a.Val != b.Val {//If the values are different, matching fails and false is returned return false } return isStructure(a.Left,b.Left) && isStructure(a.Right,b.Right) } ``````go func isSubStructure(A *TreeNode, B *TreeNode) bool { var result = false if A != nil && B != nil { //First compare the root node, and then compare the left and right subtree nodes if A.Val == B.Val { //If the root node is satisfied, it is judged that it is not a substructure result = isStructure(A,B) //Without recursion, it can also be written as the judgment of left and right subtrees } //The left subtree of the comparison is the root node and starts to traverse the comparison if !result { result = isSubStructure(A.Left,B) } //Compare the right subtree as the root node and start traversing the comparison if !result { result = isSubStructure(A.Right,B) } } return result } func isStructure(a *TreeNode, b *TreeNode) bool { if b == nil {//Description tree B has been matched (beyond the leaf node), so it returns true return true } if a == nil {//It indicates that the leaf node of tree A has been crossed, that is, the matching fails, and false is returned return false } if a.Val != b.Val {//If the values are different, matching fails and false is returned return false } return isStructure(a.Left,b.Left) && isStructure(a.Right,b.Right) } ``````go func isSubStructure(A *TreeNode, B *TreeNode) bool { var result = false if A != nil && B != nil { //First compare the root node, and then compare the left and right subtree nodes if A.Val == B.Val { //If the root node is satisfied, it is judged that it is not a substructure result = isStructure(A,B) //Without recursion, it can also be written as the judgment of left and right subtrees } //The left subtree of the comparison is the root node and starts to traverse the comparison if !result { result = isSubStructure(A.Left,B) } //Compare the right subtree as the root node and start traversing the comparison if !result { result = isSubStructure(A.Right,B) } } return result } func isStructure(a *TreeNode, b *TreeNode) bool { if b == nil {//Description tree B has been matched (beyond the leaf node), so it returns true return true } if a == nil {//It indicates that the leaf node of tree A has been crossed, that is, the matching fails, and false is returned return false } if a.Val != b.Val {//If the values are different, matching fails and false is returned return false } return isStructure(a.Left,b.Left) && isStructure(a.Right,b.Right) }
The following algorithms are very difficult. I don't know how long I can study them thoroughly. What is certain is that the update time must be later than that in Chapter 2 and Chapter 3.