11
题目:给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
返回容器可以储存的最大水量。
说明:你不能倾斜容器。
- 暴力枚举 O(n^2) 超出时间限制
func maxArea(height []int) int {
ans := 0
for i := 0; i < len(height); i++ {
for j := i + 1; j < len(height); j++ {
temp := (j - i) * min(height[i], height[j])
ans = max(temp, ans)
}
}
return ans
}
func min(x, y int) int {
if x < y {
return x
}
return y
}
func max(x, y int) int {
if x > y {
return x
}
return y
}
- 消状态 O(n)
func maxArea(height []int) int {
ans := 0
i, j := 0, len(height)-1
for i < j {
ans = max(ans, min(height[i], height[j])*(j-i))
fmt.Println(ans, i, j)
if height[i] < height[j] {
i++
} else {
j--
}
}
return ans
}
func min(x, y int) int {
if x < y {
return x
}
return y
}
func max(x, y int) int {
if x > y {
return x
}
return y
}
//执行用时:276 ms, 在所有 Go 提交中击败了5.19%的用户
//内存消耗:8.2 MB, 在所有 Go 提交中击败了91.76%的用户
12
题目:
- 模拟
var rl = []struct {
num int
symbol string
}{
{1000, "M"},
{900, "CM"},
{500, "D"},
{400, "CD"},
{100, "C"},
{90, "XC"},
{50, "L"},
{40, "XL"},
{10, "X"},
{9, "IX"},
{5, "V"},
{4, "IV"},
{1, "I"},
}
func intToRoman(num int) string {
ans := ""
for _, v := range rl {
for num >= v.num {
ans += v.symbol
num -= v.num
}
}
return ans
}
//执行用时:4 ms, 在所有 Go 提交中击败了90.14%的用户
//内存消耗:3.1 MB, 在所有 Go 提交中击败了48.49%的用户
13
题目:
- 先检索前两个字符是否在哈希表中,否则看一个字符
func romanToInt(s string) int {
ans := 0
src := map[string]int{
"M": 1000,
"CM": 900,
"D": 500,
"CD": 400,
"C": 100,
"XC": 90,
"L": 50,
"XL": 40,
"X": 10,
"IX": 9,
"V": 5,
"IV": 4,
"I": 1,
}
i := 0
for i < len(s) {
if i+1 < len(s) {
if v, ok := src[s[i:i+2]]; ok {
fmt.Println(1, s[i:i+2])
ans += v
i += 2
} else {
ans += src[s[i:i+1]]
fmt.Println(2, s[i:i+1])
i++
}
} else {
ans += src[s[i:i+1]]
i++
}
}
return ans
}
//执行用时:4 ms, 在所有 Go 提交中击败了87.80%的用户
//内存消耗:5.1 MB, 在所有 Go 提交中击败了5.27%的用户
- 前一个字符比后一个字符小则减去这个对应值,否则加上
func romanToInt(s string) int {
ans := 0
src := map[byte]int{'I': 1, 'V': 5, 'X': 10, 'L': 50, 'C': 100, 'D': 500, 'M': 1000}
for i := range s {
value := src[s[i]]
if i < len(s)-1 && value < src[s[i+1]] {
ans -= value
} else {
ans += value
}
}
return ans
}
//执行用时:4 ms, 在所有 Go 提交中击败了87.80%的用户
//内存消耗:2.7 MB, 在所有 Go 提交中击败了100.00%的用户
14
题目:编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 “”。
- 横向比较
func longestCommonPrefix(strs []string) string {
if len(strs) == 0 {
return ""
}
if len(strs) == 1 {
return strs[0]
}
prefix := strs[0]
for i := 1; i < len(strs); i++ {
prefix = lcp(prefix, strs[i])
if len(prefix) == 0 {
return ""
}
}
return prefix
}
func lcp(str1, str2 string) string {
length := min(len(str1), len(str2))
i := 0
for i < length && str1[i] == str2[i] {
i++
}
return str1[:i]
}
func min(x, y int) int {
if x < y {
return x
}
return y
}
//执行用时:0 ms, 在所有 Go 提交中击败了100.00%的用户
//内存消耗:2.2 MB, 在所有 Go 提交中击败了60.90%的用户
- 纵向比较
func longestCommonPrefix(strs []string) string {
if len(strs) == 0 {
return ""
}
if len(strs) == 1 {
return strs[0]
}
for i := 0; i < len(strs[0]); i++ {
for j := 1; j < len(strs); j++ {
if i == len(strs[j]) || strs[0][i] != strs[j][i] {
return strs[0][:i]
}
}
}
return strs[0]
}
//执行用时:0 ms, 在所有 Go 提交中击败了100.00%的用户
//内存消耗:2.2 MB, 在所有 Go 提交中击败了90.85%的用户
- 分治法
func longestCommonPrefix(strs []string) string {
if len(strs) == 0 {
return ""
}
var lcp func(int, int) string
lcp = func(start, end int) string {
if start == end {
return strs[start]
}
mid := (start + end) / 2
lcpLeft, lcpRight := lcp(start, mid), lcp(mid+1, end)
minlength := min(len(lcpLeft), len(lcpRight))
for i := 0; i < minlength; i++ {
if lcpLeft[i] != lcpRight[i] {
return lcpLeft[:i]
}
}
return lcpLeft[:minlength]
}
return lcp(0, len(strs)-1)
}
func min(x, y int) int {
if x < y {
return x
}
return y
}
//执行用时:0 ms, 在所有 Go 提交中击败了100.00%的用户
//内存消耗:2.2 MB, 在所有 Go 提交中击败了90.98%的用户
15
题目:给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请
你返回所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
- 排序+三重循环==>二重循环
func threeSum(nums []int) [][]int {
ans := [][]int{}
sort.Slice(nums, func(i, j int) bool { return nums[i] < nums[j] })
// fmt.Println(nums)
for i := 0; i < len(nums); i++ {
if i > 0 && nums[i] == nums[i-1] {
continue
}
third := len(nums) - 1
target := -1 * nums[i]
for j := i + 1; j < len(nums); j++ {
if j > i+1 && nums[j] == nums[j-1] {
continue
}
for j < third && nums[j]+nums[third] > target {
third--
}
if j == third {
break
}
if nums[j]+nums[third] == target {
ans = append(ans, []int{nums[i], nums[j], nums[third]})
}
}
}
return ans
}
//执行用时:40 ms, 在所有 Go 提交中击败了43.53%的用户
//内存消耗:8.3 MB, 在所有 Go 提交中击败了8.48%的用户
16
题目:给你一个长度为 n 的整数数组 nums 和 一个目标值 target。请你从 nums 中选出三个整数,使它们的和与 target 最接近。
返回这三个数的和。
假定每组输入只存在恰好一个解。
- 暴力三次循环
func threeSumClosest(nums []int, target int) int {
ans := math.MaxInt64
ans1 := 0
for i := 0; i < len(nums); i++ {
if i > 0 && nums[i] == nums[i-1] {
continue
}
for j := i + 1; j < len(nums); j++ {
if j > i+1 && nums[j] == nums[j-1] {
continue
}
for m := j + 1; m < len(nums); m++ {
if ans > abs(target-nums[i]-nums[j]-nums[m]) {
ans = min(ans, abs(target-nums[i]-nums[j]-nums[m]))
ans1 = nums[i] + nums[j] + nums[m]
}
}
}
}
return ans1
}
func min(x, y int) int {
if x < y {
return x
}
return y
}
func abs(x int) int {
if x < 0 {
return -x
}
return x
}
//执行用时:772 ms, 在所有 Go 提交中击败了5.09%的用户
//内存消耗:3 MB, 在所有 Go 提交中击败了28.20%的用户
- 排序+双指针
func threeSumClosest(nums []int, target int) int {
sort.Ints(nums)
ans := math.MaxInt32
update := func(cur int) {
if abs(cur-target) < abs(ans-target) {
ans = cur
}
}
for i := 0; i < len(nums); i++ {
if i > 0 && nums[i] == nums[i-1] {
continue
}
j, k := i+1, len(nums)-1
for j < k {
sum := nums[i] + nums[j] + nums[k]
if sum == target {
return sum
}
update(sum)
if sum > target {
k0 := k - 1
for k0 > j && nums[k0] == nums[k] {
k0--
}
k = k0
} else {
j0 := j + 1
for j0 < k && nums[j0] == nums[j] {
j0++
}
j = j0
}
}
}
return ans
}
func abs(x int) int {
if x < 0 {
return -x
}
return x
}
//执行用时:16 ms, 在所有 Go 提交中击败了47.91%的用户
//内存消耗:3 MB, 在所有 Go 提交中击败了69.45%的用户
17
题目:给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
- 获取第一个数字更新string表,获取下一个数字和string表结合再更新string表,以此类推
func letterCombinations(digits string) []string {
ans := []string{}
src := map[byte]string{
'2': "abc",
'3': "def",
'4': "ghi",
'5': "jkl",
'6': "mno",
'7': "pqrs",
'8': "tuv",
'9': "wxyz",
}
n := len(digits)
for i := 0; i < n; i++ {
temp := []string{}
if i == 0 {
symbolset := src[digits[i]]
for j := 0; j < len(symbolset); j++ {
temp = append(temp, string(symbolset[j]))
}
// fmt.Println(temp)
} else {
symbolset := src[digits[i]]
for _, v := range ans {
for k := 0; k < len(symbolset); k++ {
temp = append(temp, v+string(symbolset[k]))
}
}
}
ans = temp
}
return ans
}
//执行用时:0 ms, 在所有 Go 提交中击败了100.00%的用户
//内存消耗:1.9 MB, 在所有 Go 提交中击败了60.02%的用户
- 回溯
var combinations []string
var src map[string]string = map[string]string{
"2": "abc",
"3": "def",
"4": "ghi",
"5": "jkl",
"6": "mno",
"7": "pqrs",
"8": "tuv",
"9": "wxyz",
}
func letterCombinations(digits string) []string {
if len(digits) == 0 {
return []string{}
}
combinations = []string{}
backtrack(digits, 0, "")
return combinations
}
func backtrack(digits string, index int, combination string) {
if index == len(digits) {
combinations = append(combinations, combination)
} else {
digit := string(digits[index])
letters := src[digit]
lettersCount := len(letters)
for i := 0; i < lettersCount; i++ {
backtrack(digits, index+1, combination+string(letters[i]))
}
}
}
//执行用时:0 ms, 在所有 Go 提交中击败了100.00%的用户
//内存消耗:1.9 MB, 在所有 Go 提交中击败了50.75%的用户
18
题目:给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):
0 <= a, b, c, d < n
a、b、c 和 d 互不相同
nums[a] + nums[b] + nums[c] + nums[d] == target
你可以按 任意顺序 返回答案 。
- 排序+三重循环
func fourSum(nums []int, target int) [][]int {
ans := [][]int{}
sort.Ints(nums)
for i := 0; i < len(nums); i++ {
if i > 0 && nums[i] == nums[i-1] {
continue
}
for j := i + 1; j < len(nums); j++ {
if j > i+1 && nums[j] == nums[j-1] {
continue
}
// temp := target - nums[i] - nums[j]
m, n := j+1, len(nums)-1
for m < n {
sum := nums[i] + nums[j] + nums[m] + nums[n]
if sum == target {
ans = append(ans, []int{nums[i], nums[j], nums[m], nums[n]})
m0 := m + 1
for m0 < n && nums[m0] == nums[m] {
m0++
}
m = m0
n0 := n - 1
for n0 > m && nums[n0] == nums[n] {
n0--
}
n = n0
} else if sum > target {
n0 := n - 1
for n0 > m && nums[n0] == nums[n] {
n0--
}
n = n0
} else {
m0 := m + 1
for m0 < n && nums[m0] == nums[m] {
m0++
}
m = m0
}
}
}
}
return ans
}
//执行用时:20 ms, 在所有 Go 提交中击败了14.97%的用户
//内存消耗:2.7 MB, 在所有 Go 提交中击败了19.44%的用户
19
题目:给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
- 计算链表长度
func removeNthFromEnd(head *ListNode, n int) *ListNode {
temp1 := head
temp2 := head
length := 0
for temp1 != nil {
length++
temp1 = temp1.Next
}
length1 := length - n
if length==1&&length1==0{
return nil
}else if length1 ==0{
return head.Next
}
for length1 > 1 {
length1--
temp2 = temp2.Next
}
temp2.Next = temp2.Next.Next
return head
}
//执行用时:0 ms, 在所有 Go 提交中击败了100.00%的用户
//内存消耗:2.1 MB, 在所有 Go 提交中击败了99.93%的用户
- 计算链表长度优化
func getListLength(head *ListNode) (length int) {
for ; head != nil; head = head.Next {
length++
}
return
}
func removeNthFromEnd(head *ListNode, n int) *ListNode {
length := getListLength(head)
dummp := &ListNode{0, head}
cur := dummp
for i := 0; i < length-n; i++ {
cur = cur.Next
}
cur.Next = cur.Next.Next
return dummp.Next
}
//执行用时:0 ms, 在所有 Go 提交中击败了100.00%的用户
//内存消耗:2.1 MB, 在所有 Go 提交中击败了99.93%的用户
- 栈
func removeNthFromEnd(head *ListNode, n int) *ListNode {
nodes := []*ListNode{}
dummy := &ListNode{0, head}
for node := dummy; node != nil; node = node.Next {
nodes = append(nodes, node)
}
prev := nodes[len(nodes)-1-n]
prev.Next = prev.Next.Next
return dummy.Next
}
//执行用时:0 ms, 在所有 Go 提交中击败了100.00%的用户
//内存消耗:2.2 MB, 在所有 Go 提交中击败了5.53%的用户
- 双指针
func removeNthFromEnd(head *ListNode, n int) *ListNode {
dummy := &ListNode{0, head}
first, second := head, dummy
for i := 0; i < n; i++ {
first = first.Next
}
for first != nil {
first = first.Next
second = second.Next
}
second.Next = second.Next.Next
return dummy.Next
}
//执行用时:0 ms, 在所有 Go 提交中击败了100.00%的用户
//内存消耗:2.1 MB, 在所有 Go 提交中击败了99.93的用户
20
题目:给定一个只包括 ‘(’,‘)’,‘{’,‘}’,‘[’,‘]’ 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
每个右括号都有一个对应的相同类型的左括号。
- 匹配到对应括号就删除,看最终字符串是否为空
func isValid(s string) bool {
src := map[byte]byte{
')': '(',
']': '[',
'}': '{',
}
ans := ""
for i := 0; i < len(s); i++ {
if i == 0 {
ans += string(s[i])
continue
}
temp, ok := src[s[i]]
if ok && len(ans) > 0 && ans[len(ans)-1] == temp {
ans = ans[:len(ans)-1]
} else {
ans += string(s[i])
}
// fmt.Println(string(s[i]))
// fmt.Println(ans, 2)
}
return len(ans) == 0
}
//执行用时:0 ms, 在所有 Go 提交中击败了100.00%的用户
//内存消耗:6.4 MB, 在所有 Go 提交中击败了5.03%的用户