算法总结-双指针法

双指针法

运用两个指针对数组进行操作

优点:通过两个指针在一个for循环下完成两个for循环的工作

LeetCode:27.移除元素

题目链接:27. 移除元素 - 力扣(LeetCode)

给你一个数组 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] 的形式返回这两个整数的下标 index1index2

你可以假设每个输入 只对应唯一的答案 ,而且你 不可以 重复使用相同的元素。

你所设计的解决方案必须只使用常量级的额外空间。

示例 :

输入: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.三数之和

题目链接:15. 三数之和 - 力扣(LeetCode)

给你一个包含 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)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值