title: golang力扣刷题(二)
date: 2021-11-04 10:06:27
categories:
- go
tags: - 基础
力扣刷题(二)
力扣刷题 全部题目模块(30~60)
简单
搜索插入位置
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 O(log n) 的算法。
示例 1:
输入: nums = [1,3,5,6], target = 5
输出: 2
func searchInsert(nums []int, target int) int {
i := 0
j := len(nums) - 1
c := -1
for t := (i + j) / 2; i <= j; t = (i + j) / 2 {//二分法查找
if nums[t] == target { //相等输出
c = t
break
}
if nums[t] < target { //缩小范围
i = t + 1
}
if nums[t] > target {
j = t - 1
}
}
if j < 0 { //排除最左端
c = 0
} else if i > len(nums)-1 { //排除最右端
c = len(nums)
} else if nums[i] > target && target > nums[j] { //中间端
c = i
}
return c
}
执行用时:0 ms, 在所有 Go 提交中击败了100.00%的用户
内存消耗:3 MB, 在所有 Go 提交中击败了28.29%的用户
最后一个单词的长度
给你一个字符串 s,由若干单词组成,单词前后用一些空格字符隔开。返回字符串中 最后一个 单词的长度。
单词 是指仅由字母组成、不包含任何空格字符的最大子字符串。
示例 1:
输入:s = "Hello World"
输出:5
解释:最后一个单词是“World”,长度为5。
func lengthOfLastWord(s string) int {
n := 0 //记录长度
a := 0 //计数器
for _, m := range s { //遍历字符串
if m == 32 { //如果为空 a清0
a = 0
} else { //不为空 a++
a++
}
if a != 0 { //如果a不是空,则n跟着a增加
n = a
}
}
return n
}
执行用时:0 ms, 在所有 Go 提交中击败了100.00%的用户
内存消耗:2 MB, 在所有 Go 提交中击败了89.55%的用户
最大子数组和
给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
子数组 是数组中的一个连续部分。
示例 1:
输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
示例 2:
输入:nums = [1]
输出:1
func maxSubArray(nums []int) int {
max := nums[0] //max 计数
for i := 1; i < len(nums); i++ {
if nums[i]+nums[i-1] > nums[i] {
nums[i] = nums[i] + nums[i-1] //更新i 记录最大值
}
if nums[i] > max { //更新最大值
max = nums[i]
}
}
return max
}
执行用时:72 ms, 在所有 Go 提交中击败了99.93%的用户
内存消耗:9.3 MB, 在所有 Go 提交中击败了37.27%的用户
回文链表
给定一个链表的 头节点 head
**,**请判断其是否为回文链表。
如果一个链表是回文,那么链表节点序列从前往后看和从后往前看是相同的。
输入: head = [1,2,3,3,2,1]
输出: true
func reverselist(head *ListNode) (l *ListNode, r *ListNode) {
var p, q, m *ListNode //翻转函数,输入123,返回321 的头尾指针
p = head
q = head.Next
m = q.Next
if m == nil {
q.Next = p
p.Next = nil
return q, p
}
for q != nil {
q.Next = p
p = q
q = m
if m.Next != nil {
m = m.Next
} else {
q.Next = p
break
}
}
head.Next = nil
return q, head
}
func isPalindrome(head *ListNode) bool {
n := 1
head1 := head
head2 := head
for head1.Next != nil { //算出链表长度
n++
head1 = head1.Next
}
print(n)
for i := 0; i < n/2; i++ { //找到后面链表的开头
head2 = head2.Next
print(i)
}
if n > 1 && n%2 == 0 && n < 6 { //n=2,4 //排除前五个
if n == 2 {
if head.Val != head.Next.Val {
return false
}
}
if n == 4 {
if head.Next.Val != head2.Val {
return false
}
if head.Val != head2.Next.Val {
return false
}
}
}
if n > 1 && n%2 == 1 && n < 6 { //n=3,5
if n == 3 {
if head.Val != head.Next.Next.Val {
return false
}
}
if n == 5 {
head2 = head2.Next
if head.Next.Val != head2.Val {
return false
}
if head.Val != head2.Next.Val {
return false
}
}
}
if n > 5 && n%2 == 0 { //偶数 大于6的时候
head3, _ := reverselist(head2) //翻转后面链表,逐个对比
print(head3.Val)
for head3 != nil {
if head.Val == head3.Val {
head = head.Next
head3 = head3.Next
} else {
return false
}
}
}
if n>5&&n%2==1 { //奇数 大于6的时候
head2 = head2.Next
head3, _ := reverselist(head2)//翻转后面链表,逐个对比
for head3 != nil {
if head.Val == head3.Val {
head = head.Next
head3 = head3.Next
} else {
return false
}
}
}
return true
}
//这个太笨了 史上最lou代码
执行用时: 224 ms
内存消耗: 9.4 MB
func isPalindrome(head *ListNode) bool {
head1 := head
head2 := head
var p, q *ListNode
for head1 != nil && head1.Next != nil { //翻转前部分
head1 = head1.Next.Next
q = head2.Next
head2.Next = p
p = head2
head2 = q
}
if head1 != nil { //看他是不是奇数
head2 = head2.Next
}
for p != nil { //逐个对比
if p.Val != head2.Val {
return false
}
p = p.Next
head2 = head2.Next
}
return true
}
执行用时:128 ms, 在所有 Go 提交中击败了90.49%的用户
内存消耗:10.9 MB, 在所有 Go 提交中击败了21.61%的用户
func isPalindrome(head *ListNode) bool {//递归
var spalin func(*ListNode) bool
spalin = func(head1 *ListNode) bool {
if head1 != nil {
if spalin(head1.Next) == false {
return false
}
if head.Val != head1.Val {
return false
}
head = head.Next
}
return true
}
return spalin(head)
}
执行用时: 164 ms
内存消耗: 17.6 MB
中等
下一个排列
实现获取 下一个排列 的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列(即,组合出下一个更大的整数)。
如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。
必须 原地 修改,只允许使用额外常数空间。
示例 1:
输入:nums = [1,2,3]
输出:[1,3,2]
示例 2:
输入:nums = [3,2,1]
输出:[1,2,3]
func nextPermutation(nums []int) []int {
b := 0
for i := len(nums) - 1; i > 0; i-- { //从后往前遍历
if nums[i] > nums[i-1] { //如果比前一个大
a := 0
num := nums[i:] //截取切片
sort.Ints(num) //升序排列
for n := 0; n < len(num); n++ { //遍历这个排列找到比它大的最小值
if num[n] > nums[i-1] {
a = nums[i-1] //交换位置
nums[i-1] = num[n]
num[n] = a
break
}
}
sort.Ints(num) //后面的再进行升序
for j := 0; j < len(num); j++ { //插入原来的数组
nums[i] = num[j]
i++
}
break //返回
} else { //如果不大于前一个数 计数
b++
}
}
if b == len(nums)-1 { //计数等于数组长度 则全是降序
nums = sort.Ints(nums) //将它生序
}
return nums
}
执行用时:0 ms, 在所有 Go 提交中击败了100.00%的用户
内存消耗:2.5 MB, 在所有 Go 提交中击败了15.16%的用户
func isPalindrome(head *ListNode) bool {//递归
var spalin func(*ListNode) bool
spalin = func(head1 *ListNode) bool {
if head1 != nil {
if spalin(head1.Next) == false {
return false
}
if head.Val != head1.Val {
return false
}
head = head.Next
}
return true
}
return spalin(head)
}
执行用时:164 ms, 在所有 Go 提交中击败了14.99%的用户
内存消耗:17.6 MB, 在所有 Go 提交中击败了5.19%的用户
搜索旋转排序数组
整数数组 nums 按升序排列,数组中的值 互不相同 。
在传递给函数之前,nums 在预先未知的某个下标 k(0 <= k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k+1], …, nums[n-1], nums[0], nums[1], …, nums[k-1]](下标 从 0 开始 计数)。例如, [0,1,2,4,5,6,7] 在下标 3 处经旋转后可能变为 [4,5,6,7,0,1,2] 。
给你 旋转后 的数组 nums 和一个整数 target ,如果 nums 中存在这个目标值 target ,则返回它的下标,否则返回 -1 。
示例 1:
输入:nums = [4,5,6,7,0,1,2], target = 0
输出:4
func search(nums []int, target int) int {
if len(nums) >= 2 { //>=2的时候
l := 0
r := len(nums) - 1 //分别指向首尾
for l <= r {
i := (l + r) / 2
if nums[i] == target { //找到返回
return i
}
if nums[0] <= nums[i] { //前半部分部分
if nums[0] <= target && target < nums[i] {
r = i - 1
} else {
l = i + 1
}
} else {
if nums[i] < target && target <= nums[len(nums)-1] {
l = i + 1
} else {
r = i - 1
}
}
}
} else { //如果只有一个或0个的时候
if len(nums) == 1 && nums[0] == target {
return 0
} else {
return -1
}
}
return -1
}
执行用时:0 ms, 在所有 Go 提交中击败了100.00%的用户
内存消耗:2.5 MB, 在所有 Go 提交中击败了100.00%的用户
在排序数组中查找元素的第一个和最后一个位置
给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target,返回 [-1, -1]。
进阶:
你可以设计并实现时间复杂度为 O(log n) 的算法解决此问题吗?
示例 1:
输入:nums = [5,7,7,8,8,10], target = 8
输出:[3,4]
在排序数组中查找元素的第一个和最后一个位置
给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target,返回 [-1, -1]。
进阶:
你可以设计并实现时间复杂度为 O(log n) 的算法解决此问题吗?
示例 1:
输入:nums = [5,7,7,8,8,10], target = 8
输出:[3,4]
func searchRange(nums []int, target int) []int {
l := sort.SearchInts(nums, target) //找出这个数并返回下标
if l == len(nums) || nums[l] != target {
return []int{-1, -1}
}
r := sort.SearchInts(nums, target + 1) - 1 //找出比他大的数返回下标 减1
return []int{l, r}
}
执行用时:8 ms, 在所有 Go 提交中击败了40.01%的用户
内存消耗:3.9 MB, 在所有 Go 提交中击败了59.36%的用户
有效的数独
请你判断一个 9x9 的数独是否有效。只需要 根据以下规则 ,验证已经填入的数字是否有效即可。
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)
数独部分空格内已填入了数字,空白格用 ‘.’ 表示。
注意:
一个有效的数独(部分已被填充)不一定是可解的。
只需要根据以上规则,验证已经填入的数字是否有效即可。
func isValidSudoku(board [][]byte) bool {
for i := 0; i < 9; i++ { //检查每行每列
for j := 0; j < 8; j++ {
a := board[i][j]
b := board[j][i]
for k := j + 1; k < 9; k++ {
if a == board[i][k] && a != 46 { //行
return false
}
if b == board[k][i] && b != 46 { //列
return false
}
}
}
for j := 0; j < 9; j++ { //检查每个小方块
for k := i + 1; k%3 != 0; k++ { //直接从下一行检查
for h := j / 3 * 3; h < j/3*3+3; h++ {
if board[i][j] == board[k][h] && board[i][j] != 46 {
return false
}
}
}
}
}
return true
}
执行用时:4 ms, 在所有 Go 提交中击败了60.38%的用户
内存消耗:2.6 MB, 在所有 Go 提交中击败了71.78%的用户
外观数列
给定一个正整数 n ,输出外观数列的第 n 项。
「外观数列」是一个整数序列,从数字 1 开始,序列中的每一项都是对前一项的描述。
你可以将其视作是由递归公式定义的数字字符串序列:
countAndSay(1) = “1”
countAndSay(n) 是对 countAndSay(n-1) 的描述,然后转换成另一个数字字符串。
前五项如下:
1. 1
2. 11
3. 21
4. 1211
5. 111221
第一项是数字 1
描述前一项,这个数是 1 即 “ 一 个 1 ”,记作 “11”
描述前一项,这个数是 11 即 “ 二 个 1 ” ,记作 “21”
描述前一项,这个数是 21 即 “ 一 个 2 + 一 个 1 ” ,记作 “1211”
描述前一项,这个数是 1211 即 “ 一 个 1 + 一 个 2 + 二 个 1 ” ,记作 “111221”
要 描述 一个数字字符串,首先要将字符串分割为 最小 数量的组,每个组都由连续的最多 相同字符 组成。然后对于每个组,先描述字符的数量,然后描述字符,形成一个描述组。要将描述转换为数字字符串,先将每组中的字符数量用数字替换,再将所有描述组连接起来。
func countAndSay(n int) string {
s := make([]rune, 0)
c := '1'
s = append(s, c)
for i := 1; i < n; i++ { //n==1直接输出,大于1循环
d := s[0] //d==第一个字节
s2 := make([]rune, 0)
for a, b := range s { //遍历s
if a == 0 { //去掉第一个重复的
continue
}
if d != b { //遇到不一样的
s2 = append(s2, c, d) //将之前的加入
d = b //d改成现在的b
c = '1' // 计数改为1
} else { //遇到一样的 C++
c++
}
}
s2 = append(s2, c, d) //将最后的结果加入
s = s2
c = '1' //c计数改为1
}
return string(s)
}
执行用时:216 ms, 在所有 Go 提交中击败了14.13%的用户
内存消耗:7.2 MB, 在所有 Go 提交中击败了46.46%的用户
组合总和
给定一个无重复元素的正整数数组 candidates 和一个正整数 target ,找出 candidates 中所有可以使数字和为目标数 target 的唯一组合。
candidates 中的数字可以无限制重复被选取。如果至少一个所选数字数量不同,则两种组合是唯一的。
对于给定的输入,保证和为 target 的唯一组合数少于 150 个。
示例 1:
输入: candidates = [2,3,6,7], target = 7
输出: [[7],[2,2,3]]
func combinationSum(candidates []int, target int) [][]int {
sum := 0
start := 0
var s = make([][]int, 0)
var s1 = make([]int, 0)
var combination func(candidates []int, target int, sum int, start int) //定义内置函数 将两个函数分开会出错,不是函数本身错误 它系统有问题过不去
combination = func(candidates []int, target int, sum int, start int) {
if sum == target { //如果和与target相等
t := make([]int, len(s1)) //切片只是一个指向基础数组的指针,必须复制
copy(t, s1) //如果不希望影响其他切片,需要创建切片副本
s = append(s, t) //插入正确答案
return
}
for i := start; i < len(candidates); i++ {
if sum > target { //剪枝,大于 终止循环
break
}
s1 = append(s1, candidates[i]) //插入数组
sum = sum + candidates[i] //求和
combination(candidates, target, sum, i) //回溯
sum = sum - candidates[i] //撤销操作
s1 = s1[:len(s1)-1]
}
}
combination(candidates, target, sum, start)
return s
}
执行用时:0 ms, 在所有 Go 提交中击败了100.00%的用户
内存消耗:2.7 MB, 在所有 Go 提交中击败了98.66%的用户
组合总和II
给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的每个数字在每个组合中只能使用一次。
注意:解集不能包含重复的组合。
示例 1:
输入: candidates = [10,1,2,7,6,1,5], target = 8,
输出:
[
[1,1,6],
[1,2,5],
[1,7],
[2,6]
]
func combinationSum2(candidates []int, target int) [][]int {
sort.Ints(candidates) //排序
var s = make([][]int, 0) //最终输出数组
var s1 = make([]int, 0) //单个记录答案数组
vis := make([]bool, len(candidates)) //一个标记数组,去重
sum := 0 //和
star := 0 //candidates开始下标
var combin func(candidates []int, target int, sum int, star int)
combin = func(candidates []int, target int, sum int, star int) {
//根据上个题的经验 将回溯函数建立在函数内部
if sum == target { //如何和相等
t := make([]int, len(s1)) //新建答案数组 复制插入,切片是指针
copy(t, s1)
s = append(s, t)
return
}
for i := star; i < len(candidates); i++ { //从开始下标遍历
if sum > target { //大于 剪枝,后面不用遍历
break
}
// vis[i - 1] == true,说明同一树支candidates[i - 1]使用过
// vis[i - 1] == false,说明同一树层candidates[i - 1]使用过
// 要对同一树层使用过的元素进行跳过
if i > 0 && candidates[i] == candidates[i-1] && !vis[i-1] {
continue //去重
}
vis[i] = true
sum = sum + candidates[i]
s1 = append(s1, candidates[i])
combin(candidates, target, sum, i+1) //回溯
sum = sum - candidates[i]
s1 = s1[:len(s1)-1]
vis[i] = false
}
}
combin(candidates, target, sum, star)
return s
}
执行用时:4 ms, 在所有 Go 提交中击败了45.08%的用户
内存消耗:2.5 MB, 在所有 Go 提交中击败了88.90%的用户
字符串相乘
给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式。
注意:不能使用任何内置的 BigInteger 库或直接将输入转换为整数。
示例 1:
输入: num1 = "2", num2 = "3"
输出: "6"
示例 2:
输入: num1 = "123", num2 = "456"
输出: "56088"
func multiply(num1 string, num2 string) string {
if num1 == "0" || num2 == "0" {
return "0"
}
ans := "0"
m, n := len(num1), len(num2)
for i := n - 1; i >= 0; i-- {
curr := ""
add := 0
for j := n - 1; j > i; j-- {//字符串移位加0
curr += "0"
}
y := int(num2[i] - '0')
for j := m - 1; j >= 0; j-- {
x := int(num1[j] - '0')
product := x * y + add
curr = strconv.Itoa(product % 10) + curr
add = product / 10
}
for ; add != 0; add /= 10 {
curr = strconv.Itoa(add % 10) + curr
}
ans = addStrings(ans, curr)
}
return ans
}
func addStrings(num1, num2 string) string {
i, j := len(num1) - 1, len(num2) - 1
add := 0
ans := ""
for ; i >= 0 || j >= 0 || add != 0; i, j = i - 1, j - 1 {
x, y := 0, 0
if i >= 0 {
x = int(num1[i] - '0')
}
if j >= 0 {
y = int(num2[j] - '0')
}
result := x + y + add
ans = strconv.Itoa(result % 10) + ans
add = result / 10
}
return ans
}
执行用时:44 ms, 在所有 Go 提交中击败了9.51%的用户
内存消耗:6.7 MB, 在所有 Go 提交中击败了21.60%的用户
跳跃游戏2
给你一个非负整数数组 nums ,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
你的目标是使用最少的跳跃次数到达数组的最后一个位置。
假设你总是可以到达数组的最后一个位置。
示例 1:
输入: nums = [2,3,1,1,4]
输出: 2
解释: 跳到最后一个位置的最小跳跃数是 2。
从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。
示例 2:
输入: nums = [2,3,0,1,4]
输出: 2
func jump(nums []int) int { //创建一个切片记录
m := len(nums)
n1:=0
a:=0
num:=make([]int,m)
for i:=0;i<m;i++{
n2:=i+nums[i] //本次能挑到的最远值
if n2>n1{ //如果比n1大 则换值
n1=n2
a=num[i]+1 //a++ 为了确保不出错 从num[i]上加
}
for i:=1;i<=n1&&i<m;i++{ //更新这个切片 防止越界 加上i<m
if num[i]==0{ //如果里面没有值 则加上a
num[i]=a
}
}
}
return num[m-1] //最后输出最后记录值
}
执行用时:236 ms, 在所有 Go 提交中击败了5.04%的用户
内存消耗:6.1 MB, 在所有 Go 提交中击败了27.96%的用户
func jump(nums []int) int {
m := len(nums)
n1 := 0
a := 0 //记录跳跃次数
max := 0 //记录边界
for i := 0; i < m-1; i++ { //i<m-1可防止只有一个值时 程序执行for循环
n2 := i + nums[i] //最远值
if n2 > n1 { //找到跳的最大值
n1 = n2
}
if i == max { //到达边界
max = n1 //边界等于最大值
a++ //步数+1
}
}
return a
}
执行用时:20 ms, 在所有 Go 提交中击败了35.90%的用户
内存消耗:5.8 MB, 在所有 Go 提交中击败了53.87%的用户
全排列
给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。
示例 1:
输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
示例 2:
输入:nums = [0,1]
输出:[[0,1],[1,0]]
示例 3:
输入:nums = [1]
输出:[[1]]
func permute(nums []int) [][]int {
n := len(nums)
num := make([][]int, 0)
var backtrace func(path int) //内置循环函数
backtrace = func(path int) {
if path == n { //深度等于n 输出
nu := make([]int, n)
copy(nu, nums) //不然会全部改变
num = append(num, nu)
return
}
for i := path; i < n; i++ {
nums[path], nums[i] = nums[i], nums[path] //交换位置
backtrace(path + 1) //递归
nums[path], nums[i] = nums[i], nums[path] //撤销交换
}
}
backtrace(0)
return num
}
执行用时:0 ms, 在所有 Go 提交中击败了100.00%的用户
内存消耗:2.4 MB, 在所有 Go 提交中击败了99.60%的用户
func permute(nums []int) [][]int {
if len(nums) == 0 {
return nil
}
//思路是在已有的排列数组中,从头到尾见缝插针,组成新的全排列
//比如有 1,2 的情况下,插入3,就是在头插入 3,1,2;中间插入1,3,2;尾巴插入1,2,3
temp := make([][]int,0)
temp = append(temp,[]int{nums[0]})
for i:=1;i<len(nums);i++{
temp2 := temp
temp = make([][]int,0)
for j:=0;j<=i;j++{
for k:=0;k<len(temp2);k++ {
temp3 := make([]int, 0)
temp3 = append(temp3, temp2[k][0:j]...)
temp3 = append(temp3, nums[i])
temp3 = append(temp3, temp2[k][j:]...)
temp = append(temp, temp3)
}
}
}
return temp
}
全排列2
给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。
示例 1:
输入:nums = [1,1,2]
输出:
[[1,1,2],
[1,2,1],
[2,1,1]]
示例 2:
输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
旋转图像
给定一个 n × n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。
你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。
输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[[7,4,1],[8,5,2],[9,6,3]]】
func rotate(matrix [][]int) { //有点绕 背答案吧
n := len(matrix)
for i := 0; i < n/2; i++ {
for j := 0; j < (n+1)/2; j++ {
matrix[i][j], matrix[n-j-1][i], matrix[n-i-1][n-j-1], matrix[j][n-i-1] =
matrix[n-j-1][i], matrix[n-i-1][n-j-1], matrix[j][n-i-1], matrix[i][j]
}
}
}
执行用时:0 ms, 在所有 Go 提交中击败了100.00%的用户
内存消耗:2.1 MB, 在所有 Go 提交中击败了100.00%的用户
字母异位词分组
给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。
字母异位词 是由重新排列源单词的字母得到的一个新单词,所有源单词中的字母通常恰好只用一次。
示例 1:
输入: strs = ["eat", "tea", "tan", "ate", "nat", "bat"]
输出: [["bat"],["nat","tan"],["ate","eat","tea"]]
示例 2:
输入: strs = [""]
输出: [[""]]
func SortString(s string) string { //排序函数
ss := make([]rune, 0)
for _, n := range s {
ss = append(ss, n)
}
for i := 0; i < len(ss); i++ {
for j := i + 1; j < len(ss); j++ {
if ss[i] > ss[j] {
a := ss[i]
ss[i] = ss[j]
ss[j] = a
}
}
}
return string(ss)
}
func groupAnagrams(strs []string) [][]string {
mp := map[string][]string{} //建立一个字典
for _, str := range strs { //遍历字符串数组
ss := SortString(str) //排序
mp[ss] = append(mp[ss], str) //加入字典
}
ans := make([][]string, 0, len(mp))
for _, v := range mp { //将字典中的数据加入二维数组
ans = append(ans, v)
}
return ans
}
执行用时:24 ms, 在所有 Go 提交中击败了54.24%的用户
内存消耗:7.9 MB, 在所有 Go 提交中击败了71.81%的用户
Pow(x,n)
实现 pow(x, n) ,即计算 x 的 n 次幂函数(即,xn )。
示例 1:
输入:x = 2.00000, n = 10
输出:1024.00000
示例 2:
输入:x = 2.10000, n = 3
输出:9.26100
func Pow(x float64, n int) float64 { //精髓在这里 2^0 2^1 2^2 2^4 2^8
if n == 0 { //不然会超时
return 1
}
y := Pow(x, n/2)
if n%2 == 0 {
return y * y
}
return y * y * x
}
func myPow(x float64, n int) float64 {
if n > 0 {
if x < 0 {
if n%2 == 1 {
x = -Pow(-x, n)
} else {
x = Pow(-x, n)
}
} else {
x = Pow(x, n)
}
} else if n == 0 {
return 1.0
} else { //n<0
if x < 0 {
if (-n)%2 == 1 {
x = -Pow(-x, -n)
} else {
x = Pow(-x, -n)
}
} else {
x = (1 / Pow(x, -n))
}
}
return x
}
func myPow(x float64, n int) float64 { //最后结果跟x正负没有关系
if n > 0 {
x = Pow(x, n)
} else if n == 0 {
return 1.0
} else { //n<0
x = (1 / Pow(x, -n))
}
return x
}
执行用时:0 ms, 在所有 Go 提交中击败了100.00%的用户
内存消耗:1.9 MB, 在所有 Go 提交中击败了86.38%的用户
螺旋矩阵
给你一个 m
行 n
列的矩阵 matrix
,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。
输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[1,2,3,6,9,8,7,4,5]
func spiralOrder(matrix [][]int) []int {
m := len(matrix)
n := len(matrix[0])
s := make([]int, 0)
if m == 1 { //处理只有一行
for i := 0; i < n; i++ {
s = append(s, matrix[0][i])
}
} else if n == 1 {//处理只有一列
for i := 0; i < m; i++ {
s = append(s, matrix[i][0])
}
} else {
matrix2 := make([][]bool, m)
for i := 0; i < m; i++ { //创建记录数组,默认为false
matrix2[i] = make([]bool, n)
}
for i, j := 0, 0; i < m && j < n; { //循环
for j < n && matrix2[i][j] == false { //遍历到尾部,向下
s = append(s, matrix[i][j])
matrix2[i][j] = true
j++
}
if j == n || matrix2[i][j] == true { //到尾部,改i,j
j--
i++
}
for i < m && matrix2[i][j] == false { //向下遍历
s = append(s, matrix[i][j])
matrix2[i][j] = true
i++
}
if i == m || matrix2[i][j] == true {//到底部,改i,j
i--
j--
}
for j > -1 && matrix2[i][j] == false {//向左遍历
s = append(s, matrix[i][j])
matrix2[i][j] = true
j--
}
if j == -1 || matrix2[i][j] == true { //到左边,改i,j
j++
i--
}
for i > -1 && matrix2[i][j] == false {//向上遍历
s = append(s, matrix[i][j])
matrix2[i][j] = true
i--
}
if i == 0 || matrix2[i][j] == true {//到顶部,改i,j
i++
j++
if matrix2[i][j] == true { //设置结束条件
break
}
}
}
}
return s
}
执行用时:0 ms, 在所有 Go 提交中击败了100.00%的用户
内存消耗:1.9 MB, 在所有 Go 提交中击败了77.39%的用户
跳跃游戏
给定一个非负整数数组 nums ,你最初位于数组的 第一个下标 。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否能够到达最后一个下标。
示例 1:
输入:nums = [2,3,1,1,4]
输出:true
解释:可以先跳 1 步,从下标 0 到达下标 1, 然后再从下标 1 跳 3 步到达最后一个下标。
示例 2:
输入:nums = [3,2,1,0,4]
输出:false
解释:无论怎样,总会到达下标为 3 的位置。但该下标的最大跳跃长度是 0 , 所以永远不可能到达最后一个下标。
func canJump(nums []int) bool {
n:=len(nums)
boundary:=0 //设置边界
for i:=0;i<n;i++{
if (i+nums[i])>boundary{
boundary=i+nums[i] //更新边界
}
if nums[i]==0&&n>1&&i>=boundary{ //去除[0][0,1][3,0,4]
return false
}
if boundary>=n-1{ //边界超出 true
return true
}
}
return false
}
执行用时:52 ms, 在所有 Go 提交中击败了74.87%的用户
内存消耗:6.7 MB, 在所有 Go 提交中击败了75.06%的用户
合并区间
以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。
示例 1:
输入:intervals = [[1,3],[2,6],[8,10],[15,18]]
输出:[[1,6],[8,10],[15,18]]
解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].
示例 2:
输入:intervals = [[1,4],[4,5]]
输出:[[1,5]]
解释:区间 [1,4] 和 [4,5] 可被视为重叠区间。
func merge(intervals [][]int) [][]int {
for i := 0; i < len(intervals); i++ { //先从第一个值开始排序 不排序搞不了,试过了
for j := i + 1; j < len(intervals); j++ {
if intervals[i][0] > intervals[j][0] {
a := intervals[i][0]
b := intervals[i][1]
intervals[i][0] = intervals[j][0]
intervals[i][1] = intervals[j][1]
intervals[j][0] = a
intervals[j][1] = b
}
}
}
for i := 0; i < len(intervals); {
if i+1 < len(intervals)&& intervals[i][1] <= intervals[i+1][1]&&intervals[i][1]>=intervals[i+1][0] {//[a,b][c,d] d>=b>=c 时
intervals[i][1] = intervals[i+1][1] //b=d
intervals = append(intervals[:i+1], intervals[i+2:]...) //去掉后面的
i=0
} else{
if i+1 < len(intervals)&& intervals[i][1] > intervals[i+1][1] {//b>d时
intervals = append(intervals[:i+1], intervals[i+2:]...) //去掉后面的
i=0
}else{
i++ //i++
}
}
}
return intervals
}
插入区间
给你一个 无重叠的 ,按照区间起始端点排序的区间列表。
在列表中插入一个新的区间,你需要确保列表中的区间仍然有序且不重叠(如果有必要的话,可以合并区间)。
示例 1:
输入:intervals = [[1,3],[6,9]], newInterval = [2,5]
输出:[[1,5],[6,9]]
示例 2:
输入:intervals = [[1,2],[3,5],[6,7],[8,10],[12,16]], newInterval = [4,8]
输出:[[1,2],[3,10],[12,16]]
解释:这是因为新的区间 [4,8] 与 [3,5],[6,7],[8,10] 重叠。
//最笨方法
func merge(intervals [][]int) [][]int {
for i := 0; i < len(intervals); i++ { //先从第一个值开始排序 不排序搞不了,试过了
for j := i + 1; j < len(intervals); j++ {
if intervals[i][0] > intervals[j][0] {
a := intervals[i][0]
b := intervals[i][1]
intervals[i][0] = intervals[j][0]
intervals[i][1] = intervals[j][1]
intervals[j][0] = a
intervals[j][1] = b
}
}
}
for i := 0; i < len(intervals); {
if i+1 < len(intervals) && intervals[i][1] <= intervals[i+1][1] && intervals[i][1] >= intervals[i+1][0] { //[a,b][c,d] d>=b>=c 时
intervals[i][1] = intervals[i+1][1] //b=d
intervals = append(intervals[:i+1], intervals[i+2:]...) //去掉后面的
i = 0
} else {
if i+1 < len(intervals) && intervals[i][1] > intervals[i+1][1] { //b>d时
intervals = append(intervals[:i+1], intervals[i+2:]...) //去掉后面的
i = 0
} else {
i++ //i++
}
}
}
return intervals
}
func insert(intervals [][]int, newInterval []int) [][]int {
if len(intervals) == 0 { //如果长度为零,直接加入输出
intervals = append(intervals, newInterval)
} else { //直接插入 然后用上面函数重新排序 合并 最笨方法
intervals = append(intervals, newInterval)
intervals = merge(intervals)
}
return intervals
}
执行用时:92 ms, 在所有 Go 提交中击败了5.41%的用户
内存消耗:4.5 MB, 在所有 Go 提交中击败了95.68%的用户
func insert(intervals [][]int, newInterval []int) [][]int {
ans := make([][]int, 0)
acc := false //哨兵 插入变true
for _, terval := range intervals {
if newInterval[1] < terval[0] { //在左边 无交集
if acc != true {
ans = append(ans, newInterval) //先把newInterval插入 并做好标记
acc = true
}
ans = append(ans, terval) //继续插入其他元素
} else if newInterval[0] > terval[1] { //在右边 无交集
ans = append(ans, terval) // 先插入 interval newInterval先放着
} else { //有交集的情况 更改 newInterval值
newInterval[0] = min(newInterval[0], terval[0])
newInterval[1] = max(newInterval[1], terval[1])
}
}
if acc != true { //如果遍历完还没插入 则加后面
ans = append(ans, newInterval)
}
return ans
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
执行用时:8 ms, 在所有 Go 提交中击败了75.14%的用户
内存消耗:4.5 MB, 在所有 Go 提交中击败了83.78%的用户
螺旋矩阵2
给你一个正整数 n
,生成一个包含 1
到 n2
所有元素,且元素按顺时针顺序螺旋排列的 n x n
正方形矩阵 matrix
。
输入:n = 3
输出:[[1,2,3],[8,9,4],[7,6,5]]
示例 2:
输入:n = 1
输出:[[1]]
func generateMatrix(n int) [][]int {
made := make([][]int, 0)
mm := make([]int, 0)
for i := 0; i < n; i++ { //创建数组
mm = append(mm, 0)
}
for i := 0; i < n; i++ { //创建二维数组
cc := make([]int, len(mm)) //这里要copy 不然会一起改变数字
copy(cc, mm)
made = append(made, cc)
}
if n == 1 { //排除n==1的情况
made[0][0] = 1
return made
}
m := 1
for i, j := 0, 0; m < n*n+1; { //给出循环限定条件 让他一直转
if made[i][j] != 0 { //改变方向条件
i++
j++
}
for j < n-1 && made[i][j] == 0 { //从左往右
made[i][j] = m
m++
j++
}
if made[i][j] != 0 { //改变方向
j--
i++
}
for i < n-1 && made[i][j] == 0 { //从上往下
made[i][j] = m
m++
i++
}
if made[i][j] != 0 { //改变方向
i--
j--
}
for j > 0 && made[i][j] == 0 { //从右往左
made[i][j] = m
m++
j--
}
if made[i][j] != 0 { //改变方向
i--
j++
}
for i > 0 && made[i][j] == 0 { //从下往上
made[i][j] = m
m++
i--
}
}
return made
}
困难
最长有效括号
给你一个只包含 ‘(’ 和 ‘)’ 的字符串,找出最长有效(格式正确且连续)括号子串的长度。
示例 1:
输入:s = "(()"
输出:2
解释:最长有效括号子串是 "()"
type Stack struct { //栈结构
size int
top int
data []int
}
func max(x, y int) int { //输出最大值函数
if x > y {
return x
}
return y
}
func longestValidParentheses(s string) int {
s1 := Stack{ //初始化栈
size: len(s),
top: -1,
data: make([]int, len(s)+1),
}
length := 0
maxlength := 0
s1.top = 0
s1.data[s1.top] = -1 //里面输入-1
for m, a := range s { //遍历S
if string(a) == "(" { //( 入栈
s1.top++
s1.data[s1.top] = m
} else { //) 先出栈
s1.top--
if s1.top == -1 { //如果栈为空 把 m放进去 新的开始
s1.top++
s1.data[s1.top] = m
} else { //栈不为空 得到length 上面输入-1的原因
length = m - s1.data[s1.top]
maxlength = max(length, maxlength) //得到最大值
}
}
}
return maxlength
}
执行用时:0 ms, 在所有 Go 提交中击败了100.00%的用户
内存消耗:2.8 MB, 在所有 Go 提交中击败了83.89%的用户
解数独
编写一个程序,通过填充空格来解决数独问题。
数独的解法需 遵循如下规则:
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)
数独部分空格内已填入了数字,空白格用 ‘.’ 表示。
func isvalid(row int, col int, k byte, borad [][]byte) bool {
for i := 0; i < 9; i++ { //判断行是否重复
if borad[row][i] == k {
return false
}
}
for j := 0; j < 9; j++ { //判断列是否重复
if borad[j][col] == k {
return false
}
}
Row := (row / 3) * 3
Col := (col / 3) * 3
for i := Row; i < Row+3; i++ { //判断这个小方块是否重复
for j := Col; j < Col+3; j++ {
if borad[i][j] == k {
return false
}
}
}
return true //都没有重复 返回true
}
func solve(board [][]byte) bool {
for i := 0; i < 9; i++ {
for j := 0; j < 9; j++ {
if board[i][j] != '.' { //如果为数字 继续
continue
}
for k := '1'; k <= '9'; k++ { //需要判断这行 这列 这小块有没有这个数 有的话++
if isvalid(i, j, byte(k), board) { //都没有重复
board[i][j] = byte(k) //把K 填入
if solve(board) { //找到则返回
return true
} else {
board[i][j] = '.' //没找到回溯
}
}
}
return false
}
}
return true
}
func solveSudoku(board [][]byte) {
solve(board)
}
执行用时:4 ms, 在所有 Go 提交中击败了50.56%的用户
内存消耗:2 MB, 在所有 Go 提交中击败了95.10%的用户
缺失的第一个正数
给你一个未排序的整数数组 nums ,请你找出其中没有出现的最小的正整数。
请你实现时间复杂度为 O(n) 并且只使用常数级别额外空间的解决方案。
示例 1:
输入:nums = [1,2,0]
输出:3
func firstMissingPositive(nums []int) int {
n := len(nums)
for i := 0; i < n; i++ {
for nums[i] > 0 && nums[i] < n && nums[nums[i]-1] != nums[i] {
nums[i], nums[nums[i]-1] = nums[nums[i]-1], nums[i]
}//置换, 注意这里不是if for加了限制条件 可以把某位置的数直接放到原位置,如果是if的话 只换一次 换回来的数不一定在原位置
}
for i := 0; i < n; i++ {
if nums[i] != i+1 {
return i + 1
}
}
return n + 1
}
func firstMissingPositive(nums []int) int { //这他妈好狗
n := len(nums)
for i := 0; i < n; i++ {//将所有负数变为n+1
if nums[i] <= 0 {
nums[i] = n + 1
}
}
for i := 0; i < n; i++ {//将对应位置变为负数
num := abs(nums[i])
if num <= n {
fmt.Println(num-1)
nums[num - 1] = -abs(nums[num - 1])
}
}
for i := 0; i < n; i++ { //找正数下标加一 没变负数 证明这个没出现过
if nums[i] > 0 {
return i + 1
}
}
return n + 1
}
func abs(x int) int {
if x < 0 {
return -x
}
return x
}
接雨水
给定 n
个非负整数表示每个宽度为 1
的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。
示例 2:
输入:height = [4,2,0,3,2,5]
输出:9
func trap(height []int) int {
c := 0
p := 1
a := 0
b := len(height) - 1
for i := 0; a < b; { //从头往后遍历
for height[i] < p { //一个一个往上增 找到定位
i++
a++
if i == b { //越界就返回
break
}
}
for height[b] < p { //找定位
b--
if b == 0 {
break
}
}
for j := a; j < b; j++ {//遍历定位中的值
if height[j] < p {
c++
}
}
p++ //p++
}
return c
}
执行用时:1444 ms, 在所有 Go 提交中击败了5.43%的用户
内存消耗:4.4 MB, 在所有 Go 提交中击败了13.87%的用户
通配符匹配
给定一个字符串 (s) 和一个字符模式 § ,实现一个支持 ‘?’ 和 ‘*’ 的通配符匹配。
'?' 可以匹配任何单个字符。
'*' 可以匹配任意字符串(包括空字符串)。
两个字符串完全匹配才算匹配成功。
说明:
s 可能为空,且只包含从 a-z 的小写字母。
p 可能为空,且只包含从 a-z 的小写字母,以及字符 ? 和 *。
示例 1:
输入:
s = "aa"
p = "a"
输出: false
解释: "a" 无法匹配 "aa" 整个字符串。
func isMatch(s string, p string) bool {
if len(p) == 0 { //len(p)=0 len(s)=0 true len(p)=0 len(s)!=0 false
if len(s) == 0 {
return true
}
return false
}
if len(s) == 0 { //len(s)=0 len(p)!=0时 排除*
for i := 0; i < len(p); {
if p[i] == '*' {
i++
} else {
return false
}
}
return true
}
ss, pp := s[0], p[0]
if ss == pp || pp == '?' {
return isMatch(s[1:], p[1:])
} else {
if pp == '*' {
if isMatch(s, p[1:]) == true {
return true
} else {
if isMatch(s[1:], p) == true {
return true
} else {
return false
}
}
} else {
return false
}
}
return true
}
用递归做的 自认为没问题 但是超时了 很烦
func isMatch(s string, p string) bool {
m, n := len(s), len(p)
pp := make([][]bool, m+1) // 制作一个二维bool数组 表示字符串s的前i个字符和p中的前j个字符是否能匹配
for i := 0; i <= m; i++ {
pp[i] = make([]bool, n+1) //?防止数组越界 默认都为false
}
pp[0][0] = true //两个空字符串匹配
for i:=1;i<=n;i++{
if p[i-1]=='*'{
pp[0][i]=true //*匹配所有字符
}else {
break //跳出for循环 从第一个开始都为* 则为true 一直到不一样
}
}
for i:=1;i<=m;i++{ //s选一 p从一选到最后 看是否匹配
for j:=1;j<=n;j++{
if p[j-1]=='*'{ //p为*号;
pp[i][j]=pp[i][j-1]||pp[i-1][j]
}else if p[j-1]=='?'|| s[i-1]==p[j-1]{ //p为? 或者这两个相等,看它前面的匹配 他就匹配
pp[i][j]=pp[i-1][j-1]
}
}
}
return pp[m][n]
}
执行用时:20 ms, 在所有 Go 提交中击败了26.35%的用户
内存消耗:6.3 MB, 在所有 Go 提交中击败了63.81%的用户
N皇后
n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。
每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 ‘Q’ 和 ‘.’ 分别代表了皇后和空位。
输入:n = 4
输出:[[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]]
解释:如上图所示,4 皇后问题存在两个不同的解法。
N皇后2
n 皇后问题 研究的是如何将 n 个皇后放置在 n × n 的棋盘上,并且使皇后彼此之间不能相互攻击。
给你一个整数 n ,返回 n 皇后问题 不同的解决方案的数量。
输入:n = 4
输出:2
解释:如上图所示,4 皇后问题存在两个不同的解法。
排序序列
给出集合 [1,2,3,…,n],其所有元素共有 n! 种排列。
按大小顺序列出所有排列情况,并一一标记,当 n = 3 时, 所有排列如下:
"123"
"132"
"213"
"231"
"312"
"321"
给定 n 和 k,返回第 k 个排列。
示例 1:
输入:n = 3, k = 3
输出:"213"
示例 2:
输入:n = 4, k = 9
输出:"2314"