沒事的時候打算開始玩一玩leetcode,否則每天寫代碼,卻對算法沒啥認識仍是有點尷尬的。雖然說是作題,其實大部分就是爲了看看別人牛逼的思路。儘可能天天一題把~算法
給定一個整數數組和一個目標值,找出數組中和爲目標值的兩個數。 你能夠假設每一個輸入只對應一種答案,且一樣的元素不能被重複利用。 例: 給定 nums = [2, 7, 11, 15], target = 9 由於 nums[0] + nums[1] = 2 + 7 = 9 因此返回 [0, 1]
第一種方法就是便利數組,隨着數組長度增長,執行時間指數型增長。數組
#時間複雜度:O(n^2) #空間複雜度:O(1) func twoSum(nums []int, target int) []int { for firstIndex,firstNum := range nums{ for secondIndex,secondNum := range nums{ if firstIndex != secondIndex && firstNum + secondNum == target{ return []int{firstIndex, secondIndex} } } } return nil }
第二種方式是以空間換時間,把數據存在哈希表裏面,最多隻用徹底遍歷一次數組,就能獲得結果。數據結構
#時間複雜度:O(n) #空間複雜度:O(n) func twoSumHash(nums []int, target int) []int { m := make(map[int]int) for index,num := range nums{ i,ok := m[target - num] if ok { return []int{i,index} } m[num] = index } return nil }
題目連接:https://leetcode-cn.com/problems/two-sum/description/app
給定兩個非空鏈表來表示兩個非負整數。位數按照逆序方式存儲,它們的每一個節點只存儲單個數字。將兩數相加返回一個新的鏈表。ide
你能夠假設除了數字 0 以外,這兩個數字都不會以零開頭。函數
示例:測試
輸入:(2 -> 4 -> 3) + (5 -> 6 -> 4) 輸出:7 -> 0 -> 8 緣由:342 + 465 = 807
這個題主要有兩個地方卡了我一下,第一,輸入的兩個鏈表多是不同長的,第二,最後一位相加可能會進1,因此此時,輸出比輸入多一位數字,就是多一個節點。
我在思考次題目時候,千方百計的想把輸出鏈表的第一個節點,填入數字,其實能夠這樣。鏈表第一個節點能夠爲空,而後從第二個節點賦值,最後return時候,返回head.Next。咳咳,早已忘記當年學數據結構的時候,就是這麼幹的。
個人答案:優化
func addTwoNumbers(l1 *ListNode, l2 *ListNode) *ListNode { l := new(ListNode) temp := l lsum := 0 for { if l1 != nil{ lsum += l1.Val l1 = l1.Next } if l2 != nil{ lsum += l2.Val l2 = l2.Next } temp.Val = lsum % 10 lsum = lsum / 10 if lsum != 0 || l1 != nil || l2 != nil{ nextNode := new(ListNode) temp.Next = nextNode temp = temp.Next }else{ break } } return l }
網站給出的答案:網站
func addTwoNumbers2(l1 *ListNode, l2 *ListNode) *ListNode{ dummyHead := new(ListNode) p,q,curr := l1,l2,dummyHead carry := 0 for p !=nil || q != nil{ x,y := 0,0 if p != nil { x = p.Val } if q != nil { y = q.Val } sum := x + y + carry carry = sum /10 curr.Next = new(ListNode) curr = curr.Next curr.Val = sum % 10 if p !=nil{ p = p.Next } if q !=nil{ q = q.Next } } if carry > 0{ curr.Next = &ListNode{Val:carry} } return dummyHead.Next }
網站的答案會把l1和l2賦值給一個臨時變量,這樣就不會影響函數外的l1,l2,這是我所忽略的。
網站的答案,把sum和carry分紅兩個變量,加強了可讀性,我放在一塊兒,基本上就看不出來爲啥,除以10賦值給sum。而後我變量命名過於隨意。ui
看見字符串匹配的題的就慫,因此卡了好幾天不敢作。我本身的答案卻是嘗試快10次了。才經過全部的測試。坑的點仍是很多的。說下個人實現思路吧。
func lengthOfLongestSubstring(s string) int { filter := make(map[int32]int) // 比較喜歡用哈希表統計重複 lastKey := 0 // 記錄重複時,與本次重複的上一次重複點的下一位的index(非重複開始的位置) //好比當前字母的index爲10,與之重複的字母的index爲5,那麼lastKey的值就賦值爲5 max := 0 //最大連續不重複字串的長度 for k,v := range s{ //遍歷字串 index,ok := filter[v] //判斷是否發生重複 if ok { //發生重複 if k - lastKey >max{ //計算重複點到上一個重複點的長度 max = k - lastKey } for i := lastKey;i<index;i++{ //index是與當前字母重複的所在位置,刪除此位置以前的全部字母。 delete(filter, int32(s[i])) } lastKey = index+1 } filter[v] = k //新增或更新當前字母的index值 } if len(s) - lastKey > max{ //有可能中間某個點,到最後一個字母都沒有重複,因此不會觸發ok裏面的檢測,所以判斷非重複點到最後一個字母的距離。 max = len(s) - lastKey } return max }
網站給的答案:
# i和j就是字串的開始座標和結束座標。遍歷字符串s,若是當前字母,在字串i,j中沒有重複,則j加1,即字串長度加一,若是當前字母在i,j中有重複的,則刪除字串的第一個字母。由於有可能重複的字母在i,j中間,因此就會一直刪除字串的第一個字母,直到刪除至子串中沒有重複的字母。就獲得了,非重複字串。 #思路是真的好呀。以前我一直糾結怎麼,當字串中有重複字母的時候,怎麼肯定,map中刪除哪些key,網站的思路就很流暢呀!!!贊! func lengthOfLongestSubstring(s string) int { filter := make(map[uint8]int) n := len(s) i,j,max := 0,0,0 for i < n && j < n { _,ok := filter[s[j]] if !ok{ filter[s[j]] = 0 j++ if j - i > max{ max = j - i } }else { delete(filter,s[i]) i++ } } return max }
#其實放入map中的值並不須要刪除....對比一下,我寫的答案太low了。。。 func lengthOfLongestSubstring(s string) int { filter := make(map[uint8]int) n := len(s) max := 0 for i,j := 0,0; j < n; j++ { index,ok := filter[s[j]] #判斷當前字母是否在map中已存在 if ok{ #若是存在,就把index賦值給i if index > i { #好比map中有一個字母a,他的index爲3,若是當前字母也爲a,就吧以前a的index保存到i中 i = index #爲何判斷大小呢?假如a的index爲3,他前面有一個字母b,當前字母爲a,因此i爲3,若是下一個字母爲b,由於上一個a以前有一個b,因此b是存在的,可是上一個b的在字母a前面,因此i不變。這就是map不用刪除key的緣由 } } if j - i +1 > max{ max = j - i + 1 } filter[s[j]] = j+1 } return max }
題目:給兩個有序的數組,取兩個長度爲n,m的數組的中位數,而且時間複雜度爲Olog(min(n,m))
例1:
nums1 = [1, 3] nums2 = [2] 中位數是 2.0
例2:
nums1 = [1, 2] nums2 = [3, 4] 中位數是 (2 + 3)/2 = 2.5
其實這道題考的排序算法,因此哪一個排序算法的時間複雜度是O(log n)呢,還給了兩個有序的數組,第一想到的就是歸併排序的最後一步。
func findMedianSortedArrays(nums1 []int, nums2 []int) float64 { i,j := 0,0 sorted := make([]int,0) for i < len(nums1) && j < len(nums2){ if nums1[i] > nums2[j]{ sorted = append(sorted,nums2[j]) j++ }else { sorted = append(sorted,nums1[i]) i++ } } sorted = append(sorted,nums1[i:]...) sorted = append(sorted,nums2[j:]...) n := len(sorted) if n % 2 ==0{ return (float64(sorted[n/2-1]) + float64(sorted[n/2]))/2 } return float64(sorted[(n-1)/2]) }
嚶嚶嚶,網站答案看的腦袋疼。。。。看完網站的答案,我掐指一算,個人時間複雜度是O(min(n,m)),想要時間複雜度爲O(log(mint(n,m))),就得用二分法。分析過程好複雜,腦袋疼。實現也複雜,要考慮的因素好多。。。。