用golang刷LeetCode
用Go語言刷LeetCode記錄,只是為了練習Go語言,能力有限不保證都是最優解,只能在此拋轉引玉了。
數據結構和算法
數據結構和算法是程序員的命根子,沒了命根子也就沒有了尊嚴。
1. 兩數之和
題目描述
給定一個整數數組 nums 和一個目標值 target,請你在該數組中找出和為目標值的那 兩個 整數,並返回他們的數組下標。
你可以假設每種輸入只會對應一個答案。但是,你不能重復利用這個數組中同樣的元素。
示例:
給定 nums = [2, 7, 11, 15], target = 9 因為 nums[0] + nums[1] = 2 + 7 = 9 所以返回 [0, 1]
我的解法
func twoSum(nums []int, target int) []int { l := len(nums) for i:=0;i<l;i++{ for j:=i+1;j<l;j++{ if nums[i]+nums[j] == target{ return []int{i,j} } } } return []int{} }
2. 兩數相加
題目描述
給出兩個 非空 的鏈表用來表示兩個非負的整數。其中,它們各自的位數是按照 逆序 的方式存儲的,並且它們的每個節點只能存儲 一位 數字。
如果,我們將這兩個數相加起來,則會返回一個新的鏈表來表示它們的和。
您可以假設除了數字 0 之外,這兩個數都不會以 0 開頭。
示例:
輸入:(2 -> 4 -> 3) + (5 -> 6 -> 4) 輸出:7 -> 0 -> 8 原因:342 + 465 = 807
我的解法
/** * Definition for singly-linked list. * type ListNode struct { * Val int * Next *ListNode * } */ func addTwoNumbers(l1 *ListNode, l2 *ListNode) *ListNode { var ret = new(ListNode) current := ret carry := 0 for l1 != nil || l2 != nil { x, y := 0, 0 if l1 != nil { x = l1.Val l1 = l1.Next } if l2 != nil { y = l2.Val l2 = l2.Next } sum := x + y + carry current.Next = &ListNode{Val:sum%10} current = current.Next carry = sum/10 } if carry > 0{ current.Next=&ListNode{Val:carry} } return ret.Next }
3. 無重復字符的最長子串
題目描述
給定一個字符串,請你找出其中不含有重復字符的最長子串的長度。
示例1:
輸入: "abcabcbb" 輸出: 3 解釋: 因為無重復字符的最長子串是 "abc",所以其長度為 3。
示例2:
輸入: "bbbbb" 輸出: 1 解釋: 因為無重復字符的最長子串是 "b",所以其長度為 1。
示例3:
輸入: "pwwkew" 輸出: 3 解釋: 因為無重復字符的最長子串是 "wke",所以其長度為 3。 請注意,你的答案必須是 子串 的長度,"pwke" 是一個子序列,不是子串。
我的解法
func lengthOfLongestSubstring(s string) int { i := 0 max := 0 a := []rune(s) for m, c := range a { for n := i; n < m; n++ { if a[n] == c { i = n + 1 } } if m-i+1 > max { max = m - i + 1 } } return max }
4. 尋找兩個有序數組的中位數
題目描述
給定兩個大小為m和n的有序數組nums1和nums2。
請你找出這兩個有序數組的中位數,並且要求算法的時間復雜度為O(log(m + n))。
你可以假設nums1和nums2不會同時為空。 示例1:
nums1 = [1, 3] nums2 = [2] 則中位數是 2.0
示例2:
nums1 = [1, 2] nums2 = [3, 4] 則中位數是 (2 + 3)/2 = 2.5
我的解法
func findMedianSortedArrays(nums1 []int, nums2 []int) float64 { len1 := len(nums1) len2 := len(nums2) lenSum := len1+len2 if lenSum == 0 { return float64(0) } l, r := 0, 0 a := make([]int,0,lenSum) for l <len1 && r < len2{ if nums1[l] < nums2[r]{ a = append(a,nums1[l]) l++ }else { a = append(a, nums2[r]) r++ } } a = append(a, nums1[l:]...) a = append(a, nums2[r:]...) if lenSum%2 != 0 { return float64(a[lenSum/2]) }else { return (float64(a[lenSum/2-1]) + float64(a[lenSum/2]))/2 } }
7. 整數反轉
題目描述
給出一個 32 位的有符號整數,你需要將這個整數中每位上的數字進行反轉。
示例 1:
輸入: 123
輸出: 321
示例 2:
輸入: -123
輸出: -321
示例 3:
輸入: 120
輸出: 21
注意:
假設我們的環境只能存儲得下 32 位的有符號整數,則其數值范圍為 [−231, 231 − 1]。請根據這個假設,如果反轉后整數溢出那么就返回 0。
我的解法
func reverse(x int) int { var recv int for x != 0 { pop := x % 10 x /= 10 if recv*10 > 1<<31-1 || (recv*10 == 1<<31-1 && pop > 7){ return 0 } if recv*10 < -1<<31 || (recv*10 == -1<<31 && pop < 8) { return 0 } recv = recv*10+pop } return recv }
9. 回文數
題目描述
判斷一個整數是否是回文數。回文數是指正序(從左向右)和倒序(從右向左)讀都是一樣的整數。
示例 1:
輸入: 121
輸出: true
示例 2:
輸入: -121
輸出: false 解釋: 從左向右讀, 為 -121 。 從右向左讀, 為 121- 。因此它不是一個回文數。
示例 3:
輸入: 10
輸出: false 解釋: 從右向左讀, 為 01 。因此它不是一個回文數。
我的解法
func isPalindrome(x int) bool { // 如果是負數或類似10、100、1000這種就直接返回false if x < 0 || (x != 0 && x %10 == 0) { return false } // 反轉后半部分的數字,和前半部分做比較 var right int for x > right{ right = right*10 + x%10 x /= 10 } // 注意前半部分和后半部分剛好相等(1221)或正好差一位(121) return x == right || x == right/10 }
11. 盛最多水的容器
題目描述
給你 n 個非負整數 a1,a2,…,an,每個數代表坐標中的一個點 (i, ai) 。在坐標內畫 n 條垂直線,垂直線 i 的兩個端點分別為 (i, ai) 和 (i, 0)。找出其中的兩條線,使得它們與 x 軸共同構成的容器可以容納最多的水。
說明:你不能傾斜容器,且 n 的值至少為 2。
我的解法
func maxArea(height []int) int { i := 0 j := len(height) - 1 var ret int for i < j { var area int if height[i] > height[j]{ area = (j-i)* height[j] }else { area = (j-i)* height[i] } if area > ret { ret = area } if height[i] < height[j] { i++ }else { j-- } } return ret }
13. 羅馬數字轉整數
題目描述
羅馬數字包含以下七種字符: I, V, X, L,C,D 和 M。
字符 數值
I 1
V 5
X 10
L 50
C 100
D 500
M 1000
例如, 羅馬數字 2 寫做 II ,即為兩個並列的 1。12 寫做 XII ,即為 X + II 。 27 寫做 XXVII, 即為 XX + V + II 。
通常情況下,羅馬數字中小的數字在大的數字的右邊。但也存在特例,例如 4 不寫做 IIII,而是 IV。數字 1 在數字 5 的左邊,所表示的數等於大數 5 減小數 1 得到的數值 4 。同樣地,數字 9 表示為 IX。這個特殊的規則只適用於以下六種情況:
- I 可以放在 V (5) 和 X (10) 的左邊,來表示 4 和 9。
- X 可以放在 L (50) 和 C (100) 的左邊,來表示 40 和 90。
- C 可以放在 D (500) 和 M (1000) 的左邊,來表示 400 和 900。 給定一個羅馬數字,將其轉換成整數。輸入確保在 1 到 3999 的范圍內。
示例 1:
輸入: "III" 輸出: 3
示例 2:
輸入: "IV" 輸出: 4
示例 3:
輸入: "IX" 輸出: 9
示例 4:
輸入: "LVIII" 輸出: 58 解釋: L = 50, V= 5, III = 3.
示例 5:
輸入: "MCMXCIV" 輸出: 1994 解釋: M = 1000, CM = 900, XC = 90, IV = 4.
我的解法
func romanToInt(s string) int { m := map[string]int{ "I": 1, "IV": 4, "V": 5, "IX": 9, "X": 10, "XL": 40, "L": 50, "XC": 90, "C": 100, "CD": 400, "D": 500, "CM": 900, "M": 1000, } var ret int for i:=0;i<len(s);{ // 先嘗試讀兩個字符,注意索引不要越界 if i+2<=len(s)&&m[s[i:i+2]]!=0{ ret +=m[s[i:i+2]] i+=2 continue }else{ ret +=m[s[i:i+1]] i++ continue } } return ret }
14. 最長公共前綴
題目描述
編寫一個函數來查找字符串數組中的最長公共前綴。
如果不存在公共前綴,返回空字符串 ““。
示例 1:
輸入: ["flower","flow","flight"] 輸出: "fl"
示例 2:
輸入: ["dog","racecar","car"] 輸出: "" 解釋: 輸入不存在公共前綴。
說明:
所有輸入只包含小寫字母 a-z 。
我的解法
func longestCommonPrefix(strs []string) string { if len(strs) == 0{ return "" } prefix := strs[0] for i := 1; i < len(strs); i++ { for !strings.HasPrefix(strs[i], prefix) { prefix = strs[0][0 : len(prefix)-1] if prefix == "" { return "" } } } return prefix }
15. 三數之和
題目描述
給定一個包含 n 個整數的數組 nums,判斷 nums 中是否存在三個元素 a,b,c ,使得 a + b + c = 0 ?找出所有滿足條件且不重復的三元組。
注意:答案中不可以包含重復的三元組。
例如, 給定數組 nums = [-1, 0, 1, 2, -1, -4], 滿足要求的三元組集合為: [ [-1, 0, 1], [-1, -1, 2] ]
我的解法
func threeSum(nums []int) [][]int { lenNums := len(nums) ret := make([][]int, 0, 0) if lenNums < 3{ return ret } // 排序 sort.Ints(nums) for i:=0;i<lenNums;i++{ if nums[i] > 0{break} if i > 0 && nums[i] == nums[i-1]{continue} // 去重 l, r := i+1, lenNums-1 for l < r { sum := nums[i] + nums[l] + nums[r] if sum == 0 { ret = append(ret, []int{nums[i],nums[l], nums[r]}) for l< r && nums[l] == nums[l+1]{l++} // 左邊去重 for r < r && nums[r] == nums[r-1]{r--} // 后邊去重 l++ r-- } if sum > 0 {r--} if sum < 0 {l++} } } return ret }
排序+雙指針解法:
func threeSum(nums []int) [][]int { var ret [][]int l := len(nums) if l < 3 { return ret } sort.Ints(nums) // 排序 for k := 0; k < l; k++ { if nums[k] > 0 { break } if k > 0 && nums[k] == nums[k-1] { // 去重 continue } for i, j := k+1, l-1; i < j; { if j < l-1 && nums[j] == nums[j+1] { // 去重 j-- continue } sum := nums[k] + nums[i] + nums[j] if sum > 0 { j-- } else if sum < 0 { i++ } else { ret = append(ret, []int{nums[k], nums[i], nums[j]}) i++ j-- } } } return ret }
20. 有效的括號
題目描述
給定一個只包括 ‘(‘,’)‘,’{‘,’}‘,’[‘,’]‘ 的字符串,判斷字符串是否有效。
有效字符串需滿足:
- 左括號必須用相同類型的右括號閉合。
- 左括號必須以正確的順序閉合。 注意空字符串可被認為是有效字符串。
示例 1:
輸入: "()" 輸出: true
示例 2:
輸入: "()[]{}" 輸出: true
示例 3:
輸入: "(]" 輸出: false
示例 4:
輸入: "([)]" 輸出: false
示例 5:
輸入: "{[]}" 輸出: true
我的解法
func isValid(s string) bool { m := map[byte]byte{ ')':'(', ']':'[', '}':'{', } a := make([]byte, 0, len(s)/2) for _, b := range []byte(s){ if b == '(' || b == '{' || b == '['{ a = append(a, b) continue } if b == ')' || b == '}' || b == ']'{ if len(a) >0 && m[b] == a[len(a)-1]{ a = a[:len(a)-1] continue }else { return false } } } if len(a) == 0 { return true }else { return false } }
21. 合並兩個有序鏈表
題目描述
將兩個有序鏈表合並為一個新的有序鏈表並返回。新鏈表是通過拼接給定的兩個鏈表的所有節點組成的。
示例:
輸入:1->2->4, 1->3->4 輸出:1->1->2->3->4->4
我的解法
/** * Definition for singly-linked list. * type ListNode struct { * Val int * Next *ListNode * } */ func mergeTwoLists(l1 *ListNode, l2 *ListNode) *ListNode { var ret = new(ListNode) // 前置虛擬節點法 cur := ret // 定義一個保存當前節點的變量 for l1 != nil && l2 != nil { if l1.Val < l2.Val{ cur.Next = l1 l1 = l1.Next }else { cur.Next = l2 l2 = l2.Next } cur = cur.Next // 當前節點向后移 } // 追加沒遍歷到的鏈表 if l1 != nil { cur.Next = l1 } if l2 != nil { cur.Next = l2 } return ret.Next }
26. 刪除排序數組中的重復項
題目描述
給定一個排序數組,你需要在原地刪除重復出現的元素,使得每個元素只出現一次,返回移除后數組的新長度。
不要使用額外的數組空間,你必須在原地修改輸入數組並在使用 O(1) 額外空間的條件下完成。
示例 1:
給定數組 nums = [1,1,2], 函數應該返回新的長度 2, 並且原數組 nums 的前兩個元素被修改為 1, 2。 你不需要考慮數組中超出新長度后面的元素。
示例 2:
給定 nums = [0,0,1,1,1,2,2,3,3,4], 函數應該返回新的長度 5, 並且原數組 nums 的前五個元素被修改為 0, 1, 2, 3, 4。 你不需要考慮數組中超出新長度后面的元素。
說明:
為什么返回數值是整數,但輸出的答案是數組呢?
請注意,輸入數組是以“引用”方式傳遞的,這意味着在函數里修改輸入數組對於調用者是可見的。
你可以想象內部操作如下:
// nums 是以“引用”方式傳遞的。也就是說,不對實參做任何拷貝
int len = removeDuplicates(nums); // 在函數里修改輸入數組對於調用者是可見的。 // 根據你的函數返回的長度, 它會打印出數組中該長度范圍內的所有元素。 for (int i = 0; i < len; i++) { print(nums[i]); }
我的解法
注意與27題解題思路的比較。
func removeDuplicates(nums []int) int { if len(nums) == 0 { return 0 } ret := 1 for i:=0;i<len(nums)-1;{ if nums[i+1] == nums[i]{ nums = append(nums[:i], nums[i+1:]...) continue } i++ ret++ } return ret }
27. 移除元素
題目描述
給定一個數組 nums 和一個值 val,你需要原地移除所有數值等於 val 的元素,返回移除后數組的新長度。
不要使用額外的數組空間,你必須在原地修改輸入數組並在使用 O(1) 額外空間的條件下完成。
元素的順序可以改變。你不需要考慮數組中超出新長度后面的元素。
示例 1:
給定 nums = [3,2,2,3], val = 3, 函數應該返回新的長度 2, 並且 nums 中的前兩個元素均為 2。 你不需要考慮數組中超出新長度后面的元素。
示例 2:
給定 nums = [0,1,2,2,3,0,4,2], val = 2, 函數應該返回新的長度 5, 並且 nums 中的前五個元素為 0, 1, 3, 0, 4。 注意這五個元素可為任意順序。 你不需要考慮數組中超出新長度后面的元素。
說明:
為什么返回數值是整數,但輸出的答案是數組呢?
請注意,輸入數組是以“引用”方式傳遞的,這意味着在函數里修改輸入數組對於調用者是可見的。
你可以想象內部操作如下:
// nums 是以“引用”方式傳遞的。也就是說,不對實參作任何拷貝
int len = removeElement(nums, val); // 在函數里修改輸入數組對於調用者是可見的。 // 根據你的函數返回的長度, 它會打印出數組中該長度范圍內的所有元素。 for (int i = 0; i < len; i++) { print(nums[i]); }
我的解法
func removeElement(nums []int, val int) int { ret := 0 for i:=0;i<len(nums);{ if nums[i] != val { nums[ret] = nums[i] ret++ } i++ } return ret }
83. 刪除排序鏈表中的重復元素
題目描述
給定一個排序鏈表,刪除所有重復的元素,使得每個元素只出現一次。
示例 1:
輸入: 1->1->2 輸出: 1->2
示例 2:
輸入: 1->1->2->3->3 輸出: 1->2->3
我的解法
/** * Definition for singly-linked list. * type ListNode struct { * Val int * Next *ListNode * } */ func deleteDuplicates(head *ListNode) *ListNode { cur := head for cur != nil && cur.Next != nil { if cur.Val == cur.Next.Val { cur.Next = cur.Next.Next }else { cur = cur.Next } } return head }
82. 刪除排序鏈表中的重復元素 II
懂車帝一面問過這個題。
題目描述
給定一個排序鏈表,刪除所有含有重復數字的節點,只保留原始鏈表中 沒有重復出現 的數字。
示例 1:
輸入: 1->2->3->3->4->4->5 輸出: 1->2->5
示例 2:
輸入: 1->1->1->2->3 輸出: 2->3
我的解法
遞歸法:
/** * Definition for singly-linked list. * type ListNode struct { * Val int * Next *ListNode * } */ func deleteDuplicates(head *ListNode) *ListNode { if head == nil { return head } if head.Next != nil && head.Val == head.Next.Val{ for head!=nil&&head.Next !=nil && head.Val == head.Next.Val{ head = head.Next } return deleteDuplicates(head.Next) }else { head.Next = deleteDuplicates(head.Next) } return head }
前置虛假節點方法:
/** * Definition for singly-linked list. * type ListNode struct { * Val int * Next *ListNode * } */ func deleteDuplicates(head *ListNode) *ListNode { if head == nil || head.Next==nil { return head } dummy := new(ListNode) dummy.Next = head pre := dummy cur := head for cur != nil&& cur.Next!=nil{ if cur.Val == cur.Next.Val{ for cur.Next!=nil && cur.Val == cur.Next.Val{ cur = cur.Next } pre.Next = cur.Next cur = cur.Next }else { pre = cur cur = cur.Next } } return dummy.Next }
141.環形鏈表
題目描述
給定一個鏈表,判斷鏈表中是否有環。
我的解法
去映客面試問過這道題。
/** * Definition for singly-linked list. * type ListNode struct { * Val int * Next *ListNode * } */ func hasCycle(head *ListNode) bool { n1 := head // 慢指針一步一格 n2 := head // 快指針一步兩格 if head == nil || head.Next == nil { return false } for n2 != nil && n2.Next != nil { n1 = n1.Next n2 = n2.Next.Next if n1 == n2 { return true } } return false }
206. 反轉鏈表
題目描述
反轉一個單鏈表。
示例:
輸入: 1->2->3->4->5->NULL 輸出: 5->4->3->2->1->NULL
我的解法
迭代方式:
/** * Definition for singly-linked list. * type ListNode struct { * Val int * Next *ListNode * } */ func reverseList(head *ListNode) *ListNode { var pre *ListNode cur := head for cur!= nil{ tmp := cur.Next cur.Next = pre pre = cur cur = tmp } return pre }
遞歸方式:
/** * Definition for singly-linked list. * type ListNode struct { * Val int * Next *ListNode * } */ func reverseList(head *ListNode) *ListNode { if head == nil || head.Next == nil { return head } p := reverseList(head.Next) head.Next.Next = head head.Next = nil return p }
