多数元素 多数元素
解题思路
以空间换时间 ,用哈希表来记录元素出现的次数
摩尔投票法 ,因为多数元素是指出现次数大于一半的元素,因此多数元素的个数 - 其他元素的个数 >= 1
,相当于每个多数元素和其他元素两两抵消,最后至少剩余一个多数元素
解题代码
空间换时间
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 func majorityElement (nums []int ) int { hashMap := make (map [int ]int ) n := len (nums) var majElem int for i := 0 ; i < n; i++ { if _, ok := hashMap[nums[i]]; !ok { hashMap[nums[i]] = 1 } else { hashMap[nums[i]]++ } if hashMap[nums[i]] > n/2 { majElem = nums[i] break } } return majElem }
摩尔投票法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 func majorityElement (nums []int ) int { var canditate int var count int for i := 0 ; i < len (nums); i++ { if count == 0 { canditate = nums[i] } if canditate == nums[i] { count++ } else { count-- } } return canditate }
在排序数组中查找元素的第一个和最后一个位置 在排序数组中查找元素的第一个和最后一个位置
解题思路 利用二分查找 ,分别找到目标元素的左侧边界和右侧边界
解题代码 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 func searchRange (nums []int , target int ) []int { return []int {left(nums, target), right(nums, target)} } func left (nums []int , target int ) int { low, high := 0 , len (nums)-1 var mid int for low <= high { mid = (low+high)/2 if target <= nums[mid] { high = mid - 1 } else { low = mid + 1 } } if low >= len (nums) || nums[low] != target { return -1 } return low } func right (nums []int , target int ) int { low, high := 0 , len (nums)-1 var mid int for low <= high { mid = (low+high)/2 if target >= nums[mid] { low = mid + 1 } else { high = mid - 1 } } if high < 0 || nums[high] != target { return -1 } return high }
只出现一次的数字 只出现一次的数字
解题思路
首先想到用哈希表记录元素出现的次数,但是空间复杂度达到O(n)
暴力破解,每次从数组中取出一个数,从剩下的数中查找,如果找不到,那么这个数字就是只出现一次的数字。时间复杂度达O(n^2)
先排序,时间复杂度达O(nlogn)
位运算,假设数组中有2m+1
个数字,其中a[1], a[2], a[3], ..., a[m]
均出现了2次,a[m+1]
只出现了一次。那么数组中的所有元素异或之后可以写成(a[1]⊕a[1])⊕(a[2]⊕a[2])⊕...⊕(a[m]⊕a[m])⊕a[m+1]
,即可以得到0⊕0⊕...⊕0⊕a[m+1]=a[m+1]
解题代码 位运算
1 2 3 4 5 6 7 8 9 func singleNumber (nums []int ) int { var res int for _, num := range nums { res = res ^ num } return res }
比较版本号 比较版本号
解题思路 双指针法 ,两个指针i
和j
分别指向version1
和version2
的下标,分割修订号并且转化为数字,对两个版本的修订号进行比较
解题代码 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 func compareVersion (version1 string , version2 string ) int { len1, len2 := len (version1), len (version2) var i, j int for i < len1 || j < len2 { num1 := 0 for ; i < len1 && version1[i] != '.' ; i++ { num1 = num1*10 + int (version1[i]-'0' ) } i++ num2 := 0 for ; j < len2 && version2[j] != '.' ; j++ { num2 = num2*10 + int (version2[j]-'0' ) } j++ if num1 > num2 { return 1 } else if num1 < num2 { return -1 } } return 0 }
对称二叉树 对称二叉树
解题思路
递归 法,基于二叉树的深度优先 遍历。将根节点的左子树记为left
,右子树记为right
,比较left
和right
是否相等。若相等则继续进行比较,比较left
的左子树和right
的右子树、left
的右子树和right
的左子树是否相等
迭代 法,使用队列 。首先从队列中拿出两个节点left和right进行比较。将left的左子树和right的右子树放入队列;将left的右子树和right的左子树放入队列
解题代码
深度优先遍历,递归法
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 func isSymmetric (root *TreeNode) bool { return dfs(root.Left, root.Right) } func dfs (left, right *TreeNode) bool { if left == nil && right == nil { return true } if left == nil || right == nil { return false } if left.Val != right.Val { return false } return dfs(left.Left, right.Right) && dfs(left.Right, right.Left) }
迭代法,使用队列
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 func isSymmetric (root *TreeNode) bool { if root == nil { return true } queue := make ([]*TreeNode, 0 ) queue = append (queue, root.Left) queue = append (queue, root.Right) for len (queue) > 0 { left := queue[0 ] right := queue[1 ] queue = queue[2 :] if left == nil && right == nil { continue } if left == nil || right == nil { return false } if left.Val != right.Val { return false } queue = append (queue, left.Left) queue = append (queue, right.Right) queue = append (queue, left.Right) queue = append (queue, right.Left) } return true }