Leedcode算法专题训练(双指针)
算法思想
双指针
167. 两数之和 II - 输入有序数组
双指针的典型用法
- 如果两个指针指向元素的和 sum == target,那么得到要求的结果;
- 如果 sum > target,移动较大的元素,使 sum 变小一些;
- 如果 sum < target,移动较小的元素,使 sum 变大一些。
数组中的元素最多遍历一次,时间复杂度为 O(N)。只使用了两个额外变量,空间复杂度为 O(1)。
class Solution {
public int[] twoSum(int[] numbers, int target) {
if(numbers==null)return null;
int i=0;
int j=numbers.length-1;
while(i<=j){
if(numbers[i]+numbers[j]>target)j--;
else if(numbers[i]+numbers[j]<target)i++;
else return new int[]{i+1,j+1};
}
return null;
}
}
633. 平方数之和
题目描述:判断一个非负整数是否为两个整数的平方和。
可以看成是在元素为 0~target 的有序数组中查找两个数,使得这两个数的平方和为 target,如果能找到,则返回 true,表示 target 是两个整数的平方和。
本题和 167. Two Sum II - Input array is sorted 类似,只有一个明显区别:一个是和为 target,一个是平方和为 target。本题同样可以使用双指针得到两个数,使其平方和为 target。
本题的关键是右指针的初始化,实现剪枝,从而降低时间复杂度。设右指针为 x,左指针固定为 0,为了使 02 + x2 的值尽可能接近 target,我们可以将 x 取为 sqrt(target)。
因为最多只需要遍历一次 0~sqrt(target),所以时间复杂度为 O(sqrt(target))。又因为只使用了两个额外的变量,因此空间复杂度为 O(1)。
class Solution {
public boolean judgeSquareSum(int c) {
if(c<0) return false;
int i=0, j=(int)Math.sqrt(c);
while(i<=j){
int powSum =i*i+j*j;
if(powSum==c) return true;
else if(powSum>c) j--;
else i++;
}
return false;
}
}
345. 反转字符串中的元音字母
方一
Integer[] x=new Integer[]{4,6,9,10};
Set<Integer> set = new HashSet<>() ;
Collections.addAll(set,x);
for(Integer ele:set){
System.out.println(ele);
}
方二
Set<Integer> set = new HashSet<>(Arrays.asList(4,6,9,10)) ;
使用双指针,一个指针从头向尾遍历,一个指针从尾到头遍历,当两个指针都遍历到元音字符时,交换这两个元音字符。
为了快速判断一个字符是不是元音字符,我们将全部元音字符添加到集合 HashSet 中,从而以 O(1) 的时间复杂度进行该操作。
- 时间复杂度为 O(N):只需要遍历所有元素一次
- 空间复杂度 O(1):只需要使用两个额外变量
class Solution {
public static HashSet<Character> set_char =new HashSet<>(Arrays.asList('a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U'));
public String reverseVowels(String s) {
if (s == null) return null;
int i=0, j=s.length()-1;
char[] arr=s.toCharArray();
while(i<=j){
if(!set_char.contains(arr[i]))i++;
else if(!set_char.contains(arr[j]))j--;
else {
char temp=arr[i];
arr[i++]=arr[j];
arr[j--]=temp;
}
}
return new String(arr);
}
}
680. 验证回文字符串 Ⅱ
本题的关键是处理删除一个字符。在使用双指针遍历字符串时,如果出现两个指针指向的字符不相等的情况,我们就试着删除一个字符,再判断删除完之后的字符串是否是回文字符串。
在判断是否为回文字符串时,我们不需要判断整个字符串,因为左指针左边和右指针右边的字符之前已经判断过具有对称性质,所以只需要判断中间的子字符串即可。
在试着删除字符时,我们既可以删除左指针指向的字符,也可以删除右指针指向的字符。
class Solution {
public boolean validPalindrome(String s) {
for(int i=0, j=s.length()-1; i<j; i++, j--){
if(s.charAt(i)!=s.charAt(j)){
return isPalindrome(s,i,j-1) || isPalindrome(s, i+1, j);
}
}
return true;
}
private boolean isPalindrome(String s, int i, int j) {
while (i < j) {
if (s.charAt(i++) != s.charAt(j--)) {
return false;
}
}
return true;
}
}
88. 合并两个有序数组
需要从尾开始遍历,否则在 nums1 上归并得到的值会覆盖还未进行归并比较的值。
class Solution {
public void merge(int[] nums1, int m, int[] nums2, int n) {
int index1=m-1, index2=n-1;
int indexMerge = m+n-1;
while(index1>=0 || index2>=0){
if(index1<0){
nums1[indexMerge--]=nums2[index2--];
}else if(index2<0){
nums1[indexMerge--]=nums1[index1--];
}else if (nums1[index1] > nums2[index2]) {
nums1[indexMerge--] = nums1[index1--];
} else {
nums1[indexMerge--] = nums2[index2--];
}
}
}
class Solution {
public void merge(int[] nums1, int m, int[] nums2, int n) {
int len1 = m - 1;
int len2 = n - 1;
int len = m + n - 1;
while(len1 >= 0 && len2 >= 0) {
// 注意--符号在后面,表示先进行计算再减1,这种缩写缩短了代码
nums1[len--] = nums1[len1] > nums2[len2] ? nums1[len1--] : nums2[len2--];
}
// 表示将nums2数组从下标0位置开始,拷贝到nums1数组中,从下标0位置开始,长度为len2+1
System.arraycopy(nums2, 0, nums1, 0, len2 + 1);
}
}
141. 环形链表
使用双指针,一个指针每次移动一个节点,一个指针每次移动两个节点,如果存在环,那么这两个指针一定会相遇。
public class Solution {
public boolean hasCycle(ListNode head) {
Set<ListNode> nodesSeen = new HashSet<>();
while (head != null) {
if (nodesSeen.contains(head)) {
return true;
} else {
nodesSeen.add(head);
}
head = head.next;
}
return false;
}
}
public class Solution {
public boolean hasCycle(ListNode head) {
if (head == null) {
return false;
}
ListNode cur1=head;
ListNode cur2=head.next;
while(cur1!=null && cur2 != null && cur2.next != null){
if (cur1 == cur2) {
return true;
}
cur1=cur1.next;
cur2=cur2.next.next;
}
return false;
}
}
524. 通过删除字母匹配到字典里最长单词
class Solution {
int max=-1;
String result="";
public String findLongestWord(String s, List<String> d) {
for(String str: d){
int j=0;
for(int i=0;i<s.length();i++){
if(s.charAt(i)==str.charAt(j)){
j++;
if(j==str.length()){
break;
}
}
}
if(j==str.length()&&str.length()>max){
max=str.length();
result=str;
}
if(j==str.length()&&str.length()==max){
if(result.compareTo(str)>0){
result=str;
}
}
}
return result;
}
}
class Solution {
public String findLongestWord(String s, List<String> d) {
String str="";
for(String sstr:d){
for(int i=0,j=0;i<s.length()&&j<sstr.length();i++){
if(s.charAt(i)==sstr.charAt(j)) j++;
if(j==sstr.length()){
if(sstr.length()>str.length()||(sstr.length()==str.length()&&str.compareTo(sstr)>0))
str=sstr;
}
}
}
return str;
}
}
Leedcode算法专题训练(双指针)的更多相关文章
- Leedcode算法专题训练(链表)
1.发现两个链表的交点 160.两个链表的交集(容易) Leetcode /力扣 public class Solution { public ListNode getIntersectionNode ...
- Leedcode算法专题训练(搜索)
BFS 广度优先搜索一层一层地进行遍历,每层遍历都是以上一层遍历的结果作为起点,遍历一个距离能访问到的所有节点.需要注意的是,遍历过的节点不能再次被遍历. 第一层: 0 -> {6,2,1,5} ...
- Leedcode算法专题训练(分治法)
归并排序就是一个用分治法的经典例子,这里我用它来举例描述一下上面的步骤: 1.归并排序首先把原问题拆分成2个规模更小的子问题. 2.递归地求解子问题,当子问题规模足够小时,可以一下子解决它.在这个例子 ...
- Leedcode算法专题训练(二分查找)
二分查找实现 非常详细的解释,简单但是细节很重要 https://www.cnblogs.com/kyoner/p/11080078.html 正常实现 Input : [1,2,3,4,5] key ...
- Leedcode算法专题训练(排序)
排序 快速排序 用于求解 Kth Element 问题,也就是第 K 个元素的问题. 可以使用快速排序的 partition() 进行实现.需要先打乱数组,否则最坏情况下时间复杂度为 O(N2). 堆 ...
- Leedcode算法专题训练(贪心)
1. 分配饼干 455. 分发饼干 题目描述:每个孩子都有一个满足度 grid,每个饼干都有一个大小 size,只有饼干的大小大于等于一个孩子的满足度,该孩子才会获得满足.求解最多可以获得满足的孩子数 ...
- Leedcode算法专题训练(位运算)
https://www.cnblogs.com/findbetterme/p/10787118.html 看这个就完事了 1. 统计两个数的二进制表示有多少位不同 461. Hamming Dista ...
- Leedcode算法专题训练(数组与矩阵)
1. 把数组中的 0 移到末尾 283. Move Zeroes (Easy) Leetcode / 力扣 class Solution { public void moveZeroes(int[] ...
- Leedcode算法专题训练(数学)
204. 计数质数 难度简单523 统计所有小于非负整数 n 的质数的数量. class Solution { public int countPrimes(int n) { boolean[] is ...
随机推荐
- Java并发包源码学习系列:同步组件CyclicBarrier源码解析
目录 CyclicBarrier概述 案例学习 类图结构及重要字段 内部类Generation及相关方法 void reset() void breakBarrier() void nextGener ...
- Kubernetes-3.安装
docker version:19.03.14 kubernetes version:1.19.4 本文介绍使用kubeadm安装Kubernetes集群的简单过程. 目录 使用kubeadm安装k8 ...
- Arrays.Sort()中的那些排序算法
本文基于JDK 1.8.0_211撰写,基于java.util.Arrays.sort()方法浅谈目前Java所用到的排序算法,仅个人见解和笔记,若有问题欢迎指证,着重介绍其中的TimSort排序,其 ...
- CISCN-2018-Quals-note-service2
CISCN-2018-Quals-note-service2 总结 做完这道题,收获如下: 1)汇编语句jmp short s,最后编译出来的机器码为\xEB\x??,问号代表pc寄存器会往前或往后跳 ...
- 【知识点】 C++寄存器优化
作者:李春港 出处:https://www.cnblogs.com/lcgbk/p/14502076.html 目录 一.前言 二.代码实例 三.volatile作用 一.前言 在c++中什么情况下, ...
- 浅谈Dotnet的数据定位和匹配
Dotnet里,数据定位和匹配的相关编程现在变得很舒服. 最近项目紧,还要不停出差. 所以,写个短点的.最近经常用到的内容:数据定位和匹配. 数据定位 假设我们有这样一个数组: var arr ...
- python面试题,print写在for循环内和外的区别
1.统计列表中正数和负数的数量a = [1,3,5,7,0,-1,-9,-4,-5,8]b = []c = []for i in a : if i>0: b.append(i) elif i&l ...
- Java volatile关键字详解
Java volatile关键字详解 volatile是java中的一个关键字,用于修饰变量.被此关键修饰的变量可以禁止对此变量操作的指令进行重排,还有保持内存的可见性. 简言之它的作用就是: 禁止指 ...
- css3中的渐变效果
大家好,这里是demo软件园,今天为大家分享的是css3中的渐变效果. css3中的渐变需要注意的是渐变的是图片而不是颜色,而渐变又分为两种:线性渐变与径向渐变,今天我们重点介绍的是线性渐变. 1.线 ...
- Typora的一些快捷键
语法格式 快捷键 标题 # + 空格 = 一级标题, ## + 空格 =二级标题, 以此类推 shift + 数字1 =一级标题 ,shift + 数字2 =二级标题 , 以此类推 有序列表 1 ...