一、简单:
1.有效的括号
给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
**解题思路:**判断括号的有效性可以使用「栈」这一数据结构来解决。
我们遍历给定的字符串 ss。当我们遇到一个左括号时,我们会期望在后续的遍历中,有一个相同类型的右括号将其闭合。由于后遇到的左括号要先闭合,因此我们可以将这个左括号放入栈顶。
当我们遇到一个右括号时,我们需要将一个相同类型的左括号闭合。此时,我们可以取出栈顶的左括号并判断它们是否是相同类型的括号。如果不是相同的类型,或者栈中并没有左括号,那么字符串 ss 无效,返回 \text{False}False。为了快速判断括号的类型,我们可以使用哈希表存储每一种括号。哈希表的键为右括号,值为相同类型的左括号。
在遍历结束后,如果栈中没有左括号,说明我们将字符串 ss 中的所有左括号闭合,返回 \text{True}True,否则返回 \text{False}False。
注意到有效字符串的长度一定为偶数,因此如果字符串的长度为奇数,我们可以直接返回 \text{False}False,省去后续的遍历判断过程。
我这里用的是切片代替栈,思路是一样的。
func main() {
fmt.Println(isValid("{{[]}}"))
}
func isValid(s string) bool {
flag := false
m := make(map[byte]byte)
m['('] = ')'
m['['] = ']'
m['{'] = '}'
sli := make([]byte, 0)
if len(s) == 0 {
return true
}
if len(s)%2 == 1 {
return false
}
for i, b := range s {
if i == 0 && (s[i] == ')' || s[i] == ']' || s[i] == '}') {
return false
}//如果字符串第一个字符就是右括号,则返回false
if b == '(' || b == '[' || b == '{' {
sli = append(sli, byte(b))//如果字符串里有左括号,则把左括号放到切片中
} else if b == ')' || b == ']' || b == '}' {
//如果字符串中有右括号了
left := sli[len(sli)-1]//从切片中取出栈顶的左括号
sli = sli[:len(sli)-1]//更新切片
if m[left] == byte(b) {
flag = true//判断左右括号是否匹配
} else {
return false
}
}
return flag
}
运行截图:
提交截图:
出现的问题:在提交的时候报了空指针异常。但是在运行过程中并没有出现问题,所以,我就按照官方发给的代码交了上去。
2.删除有序数组中的重复项
给你一个 升序排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。
由于在某些语言中不能改变数组的长度,所以必须将结果放在数组nums的第一部分。更规范地说,如果在删除重复项之后有 k 个元素,那么 nums 的前 k 个元素应该保存最终结果。
将最终结果插入 nums 的前 k 个位置后返回 k 。
不要使用额外的空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路:
代码:
n := len(nums)
if n<2{
return n//如果数组中没有元素或只有一个元素,则不存在重复元素
}
low := 0
fast := 0
for fast<n {
if nums[low]==nums[fast]{
fast++//快指针先走
}else{
low++
nums[low] = nums[fast]//如果后一个元素和前一个元素不相等,那么就把快指针的元素放入慢指针中
fast++
}
}
nums = nums[:low+1]//更新数组
return low+1
运行截图:
提交截图:
遇到的问题:开始没有想到数组元素为1个或0个的时候
if n<2{
return n//如果数组中没有元素或只有一个元素,则不存在重复元素
}
3.移除元素
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/remove-element
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解法一:
双指针法:
func removeElement(nums []int, val int) int {
n := 0
for i := 0; i < len(nums); i ++ {
if nums[i] != val {
nums[n] = nums[i]
n++
}
}
return n
}
解法二:切片删除法
func removeElement1(nums []int, val int) int {
for i := 0; i < len(nums); {
if nums[i] == val {
nums = append(nums[:i], nums[i + 1 :]...)//如果数组中出现了val,则把后一个元素赋值给val原先的位置。
} else {
i ++
}
}
return len(nums)
}
运行截图:
提交截图:
中等:
1.三数之和:给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/3sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
func threesum(nums []int) [][]int{
var res [][]int//最后要返回的结果数组
if len(nums) <3{
return res
}
sort.Ints(nums)//给nums排序
for i:=0;i<len(nums);i++{
if nums[i]>0 {
return res
}//因为已经排好序,所以,如果出现大于0的数,后面的a+b+c一定大于0,直接返回res
if i>0 && nums[i]==nums[i-1] {
continue
}//删除重复元组
l,r:=i+1,len(nums)-1
for l<r {
sum:=nums[i]+nums[l]+nums[r]
if sum==0 {
temp:=[]int{nums[l],nums[i],nums[r]}
res=append(res,temp)
for l<r && nums[l]==nums[l+1]{
l++
}
for l<r && nums[r]==nums[r-1] {
r--
}
l++//判断左界和右界是否和下一位重复,去除重复解。同时,将 l , r l, rl,r移动到下一位置,寻找新的解。
r--
}else if sum>0 {
r--
} else if sum<0 {
l++
}
}
}
return res
}
结果截图:
提交截图:
2.盛水最多的容器
给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。
找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
返回容器可以储存的最大水量。
说明:你不能倾斜容器。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/container-with-most-water
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路:使用双指针的方法,从两边想中间移动,每次移动高度小的指针,每次计算找出最大值
代码:
func maxArea(height []int) int {
max := 0
for i, j := 0, len(height) - 1; i < j; {//定义左右两个双指针
var minHeight int
if height[i] <= height[j] {
minHeight = height[i]
i++
}else{
minHeight = height[j]
j--
}//分别从左,从右遍历数组,找到最小的高度
w := (j - i + 1) * minHeight//每次遍历的盛水面积
if w > max {
max = w
}//更新最大面积
}
return max
}
提交截图: