01
题目:给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个
整数,并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。 你可以按任意顺序返回答案。
- 第一种方法暴力枚举
func twoSum(nums []int, target int) []int {
for i,v:=range nums{
for j,m:=range nums[:i]{
if v+m == target{
return []int{i,j}
}
}
}
return []int{0,0}
}
//执行用时:32 ms, 在所有 Go 提交中击败了15.17%的用户
//内存消耗:3.4 MB, 在所有 Go 提交中击败了99.10%的用户
- 哈希表
func twoSum(nums []int, target int) []int {
src:=map[int]int{}
for i,v:=range nums{
if value,ok:=src[target-v];ok{
return []int{i,value}
}else{
src[v] = i
}
}
return []int{0,0}
}
// 执行用时:4 ms, 在所有 Go 提交中击败了94.84%的用户
// 内存消耗:4.1 MB, 在所有 Go 提交中击败了61.35%的用户
02
题目:给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
- 模拟相加过程,注意进位
func addTwoNumbers(l1 *ListNode, l2 *ListNode) (head *ListNode) {
var res *ListNode
temp := 0
for l1 != nil || l2 != nil {
n1, n2 := 0, 0
if l1 != nil {
n1 = l1.Val
l1 = l1.Next
}
if l2 != nil {
n2 = l2.Val
l2 = l2.Next
}
sum := n1 + n2 + temp
sum, temp = sum%10, sum/10
if head == nil {
head = &ListNode{Val: sum}
res = head
} else {
res.Next = &ListNode{Val: sum}
res = res.Next
}
}
if temp > 0 {
res.Next = &ListNode{Val: temp}
}
return
}
//执行用时:8 ms, 在所有 Go 提交中击败了80.69%的用户
//内存消耗:4.4 MB, 在所有 Go 提交中击败了92.84%的用户
03
题目:给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
- 暴力,特殊处理大于2的字符串,遍历字符串的各个切片,若有重复字符则保留最大值并break,若无重复则保留当前切片大小为最大值,速度过慢需优化
func lengthOfLongestSubstring(s string) int {
if len(s) < 2 {
return len(s)
}
res := 0
for j := 0; j <= len(s); j++ {
flag := false
src := map[rune]int{}
for _, v := range s[j:] {
if _, ok := src[v]; !ok {
src[v]++
} else {
flag = true
fmt.Println(src)
res = max(res, len(src))
break
}
}
if !flag {
res = max(res, len(src))
}
}
return res
}
func max(i, j int) int {
if i < j {
return j
}
return i
}
//执行用时:1340 ms, 在所有 Go 提交中击败了5.54%的用户
//内存消耗:7 MB, 在所有 Go 提交中击败了5.29%的用户
- 滑动窗口
func lengthOfLongestSubstring(s string) int {
m:=map[byte]int{}
rk,ans:=-1,0
for i:=0;i<len(s);i++{
if i!=0{
delete(m,s[i-1])
}
for rk+1<len(s)&&m[s[rk+1]]==0{
m[s[rk+1]]++
rk++
}
ans = max(ans,len(m))
}
return ans
}
func max(x,y int)int{
if x<y{
return y
}
return x
}
//执行用时:16 ms, 在所有 Go 提交中击败了17.22%的用户
//内存消耗:2.6 MB, 在所有 Go 提交中击败了72.98%的用户
04
题目:给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。算法的时间复杂度应该为 O(log (m+n)) 。——困难题
- 合并数组
func findMedianSortedArrays(nums1 []int, nums2 []int) float64 { //O(MAX(m,n))
m := len(nums1)
n := len(nums2)
nums := make([]int, m+n)
m1, n1, i := 0, 0, 0
for m1 < m || n1 < n {
if m1 < m && n1 < n {
if nums1[m1] < nums2[n1] {
nums[i] = nums1[m1]
m1++
} else {
nums[i] = nums2[n1]
n1++
}
} else if n1 < n {
nums[i] = nums2[n1]
n1++
} else if m1 < m {
nums[i] = nums1[m1]
m1++
}
i++
}
var res float64
if (m+n)%2 == 0 {
res = (float64(nums[(m+n)/2]) + float64(nums[(m+n)/2-1])) / 2
} else {
res = float64(nums[(m+n)/2])
}
return res
}
//执行用时:12 ms, 在所有 Go 提交中击败了73.24%的用户
//内存消耗:5.4 MB, 在所有 Go 提交中击败了33.61%的用户
- 直接找两个数组第K位的数
func findMedianSortedArrays(nums1 []int, nums2 []int) float64 {
totallength := len(nums1) + len(nums2)
if (totallength)%2 == 1 {
midIndex := totallength/2 + 1
return float64(getKthElement(nums1, nums2, midIndex))
} else {
midIndex1, midIndex2 := totallength/2, totallength/2+1
return float64(getKthElement(nums1, nums2, midIndex1)+getKthElement(nums1, nums2, midIndex2)) / 2.0
}
}
func getKthElement(nums1, nums2 []int, k int) int { //二分查找两个表中第k小的数
index1, index2 := 0, 0
for {
if index1 == len(nums1) {
return nums2[index2+k-1]
}
if index2 == len(nums2) {
return nums1[index1+k-1]
}
if k == 1 {
return min(nums1[index1], nums2[index2])
}
half := k / 2
newIndex1 := min(index1+half, len(nums1)) - 1
newIndex2 := min(index2+half, len(nums2)) - 1
pivot1, pivot2 := nums1[newIndex1], nums2[newIndex2]
if pivot1 <= pivot2 {
k -= (newIndex1 - index1 + 1)
index1 = newIndex1 + 1
} else {
k -= (newIndex2 - index2 + 1)
index2 = newIndex2 + 1
}
}
}
func min(x, y int) int {
if x < y {
return x
}
return y
}
//执行用时:20 ms, 在所有 Go 提交中击败了14.00%的用户
//内存消耗:4.9 MB, 在所有 Go 提交中击败了53.03%的用户
05
题目:给你一个字符串 s,找到 s 中最长的回文子串。如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。
- 动态规划
func longestPalindrome(s string) string {
length := len(s)
if length <= 1 {
return s
}
dp := make([][]bool, length)
start := 0
maxlen := 1
for r := 0; r < length; r++ {
dp[r] = make([]bool, length)
dp[r][r] = true
for l := 0; l < r; l++ {
if s[l] == s[r] && (r-1 < l+1 || dp[l+1][r-1]) {
dp[l][r] = true
} else {
dp[l][r] = false
}
if dp[l][r] {
curlen := r - l + 1
if curlen > maxlen {
maxlen = curlen
start = l
}
}
}
}
return s[start : start+maxlen]
}
//执行用时:96 ms, 在所有 Go 提交中击败了13.25%的用户
//内存消耗:6.7 MB, 在所有 Go 提交中击败了16.68%的用户
- 中心扩散
func longestPalindrome(s string) string {
if s == "" {
return ""
}
start, end := 0, 0
for i := 0; i < len(s); i++ {
start1, end1 := expandAroundCenter(s, i, i)
start2, end2 := expandAroundCenter(s, i, i+1)
if end1-start1 > end-start {
start, end = start1, end1
}
if end2-start2 > end-start {
start, end = start2, end2
}
}
return s[start : end+1]
}
func expandAroundCenter(s string, left, right int) (int, int) {
for ; left >= 0 && right < len(s) && s[left] == s[right]; left, right = left-1, right+1 {
}
return left + 1, right - 1
}
//执行用时:4 ms, 在所有 Go 提交中击败了92.03%的用户
//内存消耗:2.3 MB, 在所有 Go 提交中击败了82.58%的用户
06
题目:将一个给定字符串 s 根据给定的行数 numRows ,以从上往下、从左到右进行 Z 字形排列。
比如输入字符串为 “PAYPALISHIRING” 行数为 3 时,排列如下:
之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:“PAHNAPLSIIGYIR”。
请你实现这个将字符串进行指定行数变换的函数:
string convert(string s, int numRows);
- 暴力
func convert(s string, numRows int) string {
if numRows <= 1 {
return s
}
strs := make([]string, numRows)
// fmt.Println(strs[1] + "123")
i := 0
j := 0
flag := false
for i < len(s) {
if j == -1 {
flag = false
j = 1
} else if j == numRows {
flag = true
j = numRows - 2
}
strs[j] += string(s[i])
if flag {
j--
} else {
j++
}
i++
}
// fmt.Println(strs)
res := ""
for _, v := range strs {
res += v
}
return res
}
//执行用时:8 ms, 在所有 Go 提交中击败了70.88%的用户
//内存消耗:6.9 MB, 在所有 Go 提交中击败了30.88%的用户
07
题目:给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。
如果反转后整数超过 32 位的有符号整数的范围 [−231,231 − 1] ,就返回 0。
假设环境不允许存储 64 位整数(有符号或无符号)。
- 暴力
func reverse(x int) int {
flag := false
if x < 0 {
x = -x
} else {
flag = true
}
res := 0
for x > 0 {
temp := x % 10
res = res*10 + temp
x /= 10
}
if res >= int(math.Pow(2, 31)) {
return 0
}
if flag {
return res
}
return -res
}
//执行用时:0 ms, 在所有 Go 提交中击败了100.00%的用户
//内存消耗:2 MB, 在所有 Go 提交中击败了14.86%的用户
08
题目:
- 模拟
func myAtoi(s string) int {
s = strings.TrimSpace(s)
i := 0
res := 0
flag := true
for i < len(s) {
if i == 0 {
if s[i] == '-' {
flag = false
i++
continue
} else if s[i] == '+' {
i++
continue
}
}
if s[i] >= '0' && s[i] <= '9' {
res = res*10 + int(s[i]-'0')
if flag && res > 2147483647 {
return 2147483647
} else if !flag && res > 2147483648 {
return -2147483648
}
} else {
break
}
i++
}
fmt.Println(res)
if flag {
return res
}
return -res
}
//执行用时:0 ms, 在所有 Go 提交中击败了100.00%的用户
//内存消耗:2.1 MB, 在所有 Go 提交中击败了37.43%的用户
- 状态机
func myAtoi(s string) int {
const (
START = iota
SIGNED
IN_NUMBER
END
)
table := map[int][4]int{
START: [4]int{START, SIGNED, IN_NUMBER, END},
SIGNED: [4]int{END, END, IN_NUMBER, END},
IN_NUMBER: [4]int{END, END, IN_NUMBER, END},
END: [4]int{END, END, END, END},
}
getCol := func(c byte) int {
if c == ' ' {
return 0
}
if c == '+' || c == '-' {
return 1
}
if c >= '0' && c <= '9' {
return 2
}
return 3
}
state := START
sign := 1
ans := 0
for i := range s {
state = table[state][getCol(s[i])]
if state == IN_NUMBER {
ans = ans*10 + int(s[i]-'0')
if ans*sign > math.MaxInt32 {
return math.MaxInt32
}
if ans*sign < math.MinInt32 {
return math.MinInt32
}
} else if state == SIGNED {
if s[i] == '-' {
sign = -1
}
}
}
return ans * sign
}
//执行用时:0 ms, 在所有 Go 提交中击败了100.00%的用户
//内存消耗:2.1 MB, 在所有 Go 提交中击败了21.28%的用户
09
题目:给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false 。
回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。
例如,121 是回文,而 123 不是。
- 暴力
func isPalindrome(x int) bool {
if x < 0 {
return false
}
s := strconv.Itoa(x)
if len(s) == 1 {
return true
}
i, j := 0, len(s)-1
for i < j {
if s[i] != s[j] {
return false
}
i++
j--
}
return true
}
//执行用时:24 ms, 在所有 Go 提交中击败了14.56%的用户
//内存消耗:4.6 MB, 在所有 Go 提交中击败了35.59%的用户
- 翻转数字判断是否相同
func isPalindrome(x int) bool {
m := x
temp := 0
for x > 0 {
temp = temp*10 + x%10
x /= 10
}
fmt.Println(temp)
return temp == m
}
//执行用时:20 ms, 在所有 Go 提交中击败了28.86%的用户
//内存消耗:4.5 MB, 在所有 Go 提交中击败了42.43%的用户
10
题目:给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 ‘.’ 和 ‘’ 的正则表达式匹配。
‘.’ 匹配任意单个字符
'’ 匹配零个或多个前面的那一个元素
所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。——困难题
- 动态规划
func isMatch(s string, p string) bool {
m, n := len(s), len(p)
matchs := func(i, j int) bool {
if i == 0 {
return false
}
if p[j-1] == '.' {
return true
}
return s[i-1] == p[j-1]
}
//初始化动态规划数组
f := make([][]bool, m+1)
for i := 0; i < len(f); i++ {
f[i] = make([]bool, n+1)
}
f[0][0] = true
for i := 0; i <= m; i++ {
for j := 1; j <= n; j++ {
if p[j-1] == '*' {
f[i][j] = f[i][j] || f[i][j-2]
if matchs(i, j-1) {
f[i][j] = f[i][j] || f[i-1][j]
}
} else if matchs(i, j) {
f[i][j] = f[i][j] || f[i-1][j-1]
}
}
}
return f[m][n]
}
//执行用时:0 ms, 在所有 Go 提交中击败了100.00%的用户
//内存消耗:2.2 MB, 在所有 Go 提交中击败了28.21%的用户