算法思想

双指针

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. 反转字符串中的元音字母

集合Set添加多个元素

方一

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算法专题训练(双指针)的更多相关文章

  1. Leedcode算法专题训练(链表)

    1.发现两个链表的交点 160.两个链表的交集(容易) Leetcode /力扣 public class Solution { public ListNode getIntersectionNode ...

  2. Leedcode算法专题训练(搜索)

    BFS 广度优先搜索一层一层地进行遍历,每层遍历都是以上一层遍历的结果作为起点,遍历一个距离能访问到的所有节点.需要注意的是,遍历过的节点不能再次被遍历. 第一层: 0 -> {6,2,1,5} ...

  3. Leedcode算法专题训练(分治法)

    归并排序就是一个用分治法的经典例子,这里我用它来举例描述一下上面的步骤: 1.归并排序首先把原问题拆分成2个规模更小的子问题. 2.递归地求解子问题,当子问题规模足够小时,可以一下子解决它.在这个例子 ...

  4. Leedcode算法专题训练(二分查找)

    二分查找实现 非常详细的解释,简单但是细节很重要 https://www.cnblogs.com/kyoner/p/11080078.html 正常实现 Input : [1,2,3,4,5] key ...

  5. Leedcode算法专题训练(排序)

    排序 快速排序 用于求解 Kth Element 问题,也就是第 K 个元素的问题. 可以使用快速排序的 partition() 进行实现.需要先打乱数组,否则最坏情况下时间复杂度为 O(N2). 堆 ...

  6. Leedcode算法专题训练(贪心)

    1. 分配饼干 455. 分发饼干 题目描述:每个孩子都有一个满足度 grid,每个饼干都有一个大小 size,只有饼干的大小大于等于一个孩子的满足度,该孩子才会获得满足.求解最多可以获得满足的孩子数 ...

  7. Leedcode算法专题训练(位运算)

    https://www.cnblogs.com/findbetterme/p/10787118.html 看这个就完事了 1. 统计两个数的二进制表示有多少位不同 461. Hamming Dista ...

  8. Leedcode算法专题训练(数组与矩阵)

    1. 把数组中的 0 移到末尾 283. Move Zeroes (Easy) Leetcode / 力扣 class Solution { public void moveZeroes(int[] ...

  9. Leedcode算法专题训练(数学)

    204. 计数质数 难度简单523 统计所有小于非负整数 n 的质数的数量. class Solution { public int countPrimes(int n) { boolean[] is ...

随机推荐

  1. java数据类型(基础篇)

    public class note02 { public static void main(String[] args) { //八大基本数据类型 //1.整数 byte num1 = 1; shor ...

  2. ASP.NET Core中如何对不同类型的用户进行区别限流

    老板提出了一个新需求,从某某天起,免费用户每天只能查询100次,收费用户100W次. 这是一个限流问题,聪明的你也一定想到了如何去做:记录用户每一天的查询次数,然后根据当前用户的类型使用不同的数字做比 ...

  3. 调用Config.ini类

    private static string sPath = @Directory.GetCurrentDirectory() + "\\config.ini"; [DllImpor ...

  4. 将springboot项目部署到服务器的tomcat中无法访问

    第一步:让启动类继承SpringBootServletInitializer,并重写configure方法,关键代码如下 @SpringBootApplication public class MyS ...

  5. Element-UI远程搜索功能详解

    官方代码: <template> <div> <el-autocomplete v-model="state" :fetch-suggestions= ...

  6. NodeJs 入门到放弃 — 入门基本介绍(一)

    码文不易啊,转载请带上本文链接呀,感谢感谢 https://www.cnblogs.com/echoyya/p/14450905.html 目录 码文不易啊,转载请带上本文链接呀,感谢感谢 https ...

  7. macOS启动Kafka

    目录 kafka目录结构 先启动zookeeper 后启动kafka 创建topic 创建一个生产者 创建一个消费者 kafka目录结构 # kafka安装目录 /usr/local/Cellar/k ...

  8. 漏洞复现-ActiveMq任意文件写入漏洞(CVE-2016-3088)

          0x00 实验环境 攻击机:Win 10 靶机也可作为攻击机:Ubuntu18 (docker搭建的vulhub靶场) 0x01 影响版本 未禁用PUT.MOVE等高危方法的ActiveM ...

  9. [Redis知识体系] 一文全面总结Redis知识体系

    本系列主要对Redis知识体系进行详解.@pdai Redis教程 - Redis知识体系详解 知识体系 学习资料 知识体系 知识体系 相关文章 首先,我们通过学习Redis的概念基础,了解它适用的场 ...

  10. 关于主机不能访问虚拟机的web服务解决

    centos7默认并没有开启80端口,我们只有开启就行 [root@localhost sysconfig]# firewall-cmd --permanent --add-port=3032/tcp ...