双指针法
运用两个指针对数组进行操作
优点:通过两个指针在一个for循环下完成两个for循环的工作
LeetCode: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。
你不需要考虑数组中超出新长度后面的元素。
双指针法(快慢指针法): 通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。
定义快慢指针
- 快指针:寻找新数组的元素 ,新数组就是不含有目标元素的数组
- 慢指针:指向更新 新数组下标的位置
Go解法:
func removeElement(nums []int, val int) int {
fast, slow := 0, 0
for fast = 0; fast < len(nums); fast++ {
if nums[fast] != val {
nums[slow] = nums[fast]
slow++
}
}
return slow
}
时间复杂度:O(n)
LeetCode:344.反转字符串
题目链接:344. 反转字符串 - 力扣(LeetCode)
编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。
示例 1:
输入:[“h”,“e”,“l”,“l”,“o”]
输出:[“o”,“l”,“l”,“e”,“h”]示例 2:
输入:[“H”,“a”,“n”,“n”,“a”,“h”]
输出:[“h”,“a”,“n”,“n”,“a”,“H”]
我们定义两个指针(也可以说是索引下标),一个从字符串前面,一个从字符串后面,两个指针同时向中间移动,并交换元素。
func reverseString(s []byte) {
for i, j := 0, len(s)-1; i < len(s)/2; i++ {
s[i], s[j] = s[j], s[i]
j--
}
}
LeetCode:151.翻转字符串里的单词
题目链接:151. 反转字符串中的单词 - 力扣(LeetCode)
给定一个字符串,逐个翻转字符串中的每个单词。
示例 1:
输入: “the sky is blue”
输出: “blue is sky the”示例 2:
输入: " hello world! "
输出: “world! hello”
解释: 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。示例 3:
输入: “a good example”
输出: “example good a”
解释: 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。
解题思路:
- 移除多余空格
- 将整个字符串反转
- 将每个单词反转
func reverseWords(s string) string {
//变成字符切片
c := []byte(s)
//去掉空格
fast, slow := 0, 0
for fast < len(c) {
if c[fast] != ' ' {
if fast < len(c) && slow != 0 {
c[slow] = ' '
slow++
}
for fast < len(c) && c[fast] != ' ' {
c[slow] = c[fast]
fast++
slow++
}
}
fast++
}
c = c[:slow]
//整体反转
slices.Reverse(c)
//反转单词
for fast, slow = 0, 0; fast < len(c); fast++ {
if c[fast] == ' ' {
slices.Reverse(c[slow:fast])
fast++
slow = fast
}
if fast == len(c)-1 {
slices.Reverse(c[slow:])
fast++
slow = fast
}
}
return string(c)
}
时间复杂度: O(n)
LeetCode:167.两数之和 II - 输入有序数组
题目链接:167. 两数之和 II - 输入有序数组 - 力扣(LeetCode)
给你一个下标从 1 开始的整数数组
numbers
,该数组已按 非递减顺序排列 ,请你从数组中找出满足相加之和等于目标数target
的两个数。如果设这两个数分别是numbers[index1]
和numbers[index2]
,则1 <= index1 < index2 <= numbers.length
。以长度为 2 的整数数组
[index1, index2]
的形式返回这两个整数的下标index1
和index2
。你可以假设每个输入 只对应唯一的答案 ,而且你 不可以 重复使用相同的元素。
你所设计的解决方案必须只使用常量级的额外空间。
示例 :
输入:numbers = [2,7,11,15], target = 9
输出:[1,2]
解释:2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。返回 [1, 2] 。
使用两个指针分别指向最小的元素和最大的元素
如果两个指针指向元素的和 sum==target,那么得到要求的结果
如果 sum>target,移动较大的元素,使 sum 变小一些
如果 sum<target,移动较小的元素,使 sum 变大一些
func twoSum(numbers []int, target int) []int {
left, right := 0, len(numbers)-1
for left < right {
temp := numbers[left] + numbers[right]
if temp < target {
left++
}
if temp > target {
right--
}
if temp == target {
return []int{left + 1, right + 1}
}
}
return nil
}
时间复杂度:O(n)
LeetCode:15.三数之和
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。
注意: 答案中不可以包含重复的三元组。
示例:
给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为: [ [-1, 0, 1], [-1, -1, 2] ]
首先将数组排序,然后有一层for循环,i从下标0的地方开始,同时定一个下标left 定义在i+1的位置上,定义下标right 在数组结尾的位置上。
依然还是在数组中找到 abc 使得a + b +c =0,我们这里相当于 a = nums[i],b = nums[left],c = nums[right]。
接下来如何移动left 和right呢, 如果nums[i] + nums[left] + nums[right] > 0 就说明 此时三数之和大了,因为数组是排序后了,所以right下标就应该向左移动,这样才能让三数之和小一些。
如果 nums[i] + nums[left] + nums[right] < 0 说明 此时 三数之和小了,left 就向右移动,才能让三数之和大一些,直到left与right相遇为止。
func threeSum(nums []int) [][]int {
sort.Ints(nums)
result := [][]int{}
for i := 0; i < len(nums)-2; i++ {
j := i + 1
k := len(nums) - 1
if i > 0 && nums[i] == nums[i-1] {
continue
}
if nums[i]+nums[i+1]+nums[i+2] > 0 {
break
}
if nums[i]+nums[k]+nums[k-1] < 0 {
continue
}
for j < k {
temp := nums[i] + nums[j] + nums[k]
if temp > 0 {
k--
} else if temp < 0 {
j++
}
if temp == 0 {
result = append(result, []int{nums[i], nums[j], nums[k]})
j++
k--
for j < k && nums[j] == nums[j-1] {
j++
}
for j < k && k < len(nums)-1 && nums[k] == nums[k+1] {
k--
}
}
}
}
return result
}
时间复杂度:O(n^2)