算法-双指针(Java实现)

算法-双指针(Java实现)

双指针-合并两个有序的数组
双指针-判断是否是回文字符串
双指针-合并区间
双指针-最小覆盖子串
双指针-反转字符串
双指针-最长无重复子数组
双指针-盛水最多的容器
双指针-接雨水问题

双指针-合并两个有序的数组

合并两个有序的数组

描述:给出一个有序的整数数组 A 和有序的整数数组 B ,请将数组 B 合并到数组 A 中,变成一个有序的升序数组
数据范围: 0≤n,m≤100,∣Ai∣<=100,∣Bi∣<=100

注意:
1.保证 A 数组有足够的空间存放 B 数组的元素, A 和 B 中初始的元素数目分别为 m 和 n,A的数组空间大小为 m+n
2.不要返回合并的数组,将数组 B 的数据合并到 A 里面就好了,且后台会自动将合并后的数组 A 的内容打印出来,所以也不需要自己打印
3.A 数组在[0,m-1]的范围也是有序的

示例2

输入:
[1,2,3],[2,5,6]

返回值:
[1,2,2,3,5,6]

import java.util.*;
public class Solution {
   public void merge(int A[], int m, int B[], int n) {
        int[] res = new int[m+n];  
        int i=0,j=0,r=0;
        while(i<m && j<n){      //遍历A.B中的元素
            if(A[i]<=B[j]){    //如果A<=B,A先放
                res[r++] = A[i++];
            }else{             //如果A>B,B先放
                res[r++] = B[j++];
            }
        }
        //如果A,B其中有一个遍历完,另一个没遍历完,则将未遍历完的数组中的元素全部加入res中
        while(i<m){     //当A中的元素未遍历完时,将A中剩下的元素全部放入res中
            res[r++]=A[i++];
        }
        while(j<n){     //当B中的元素未遍历完时,将B中剩下的元素全部放入res中
            res[r++]=B[j++];
        }
        for(int k=0;k<res.length;k++){ //最后将数组res中的元素全部存入数组A中
            A[k]=res[k];
        }
    }
}

双指针-判断是否是回文字符串

描述:给定一个长度为 n 的字符串,请编写一个函数判断该字符串是否回文。如果是回文请返回true,否则返回false。
字符串回文指该字符串正序与其逆序逐字符一致。

数据范围:0<n≤1000000
要求:空间复杂度 O(1)O(1),时间复杂度 O(n)O(n)

import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     * 
     * @param str string字符串 待判断的字符串
     * @return bool布尔型
     */
    public boolean judge (String str) {
        // write code here
        // 判断特殊情况
        if (str == null || str.length() == 0) {
            return false;
        }
        // 定义双指针,不相同则不是回文串
        for (int i = 0, j = str.length()-1; i < j; i++, j--){
            if (str.charAt(i) != str.charAt(j)) return false;
        }

        return true;
    }
}

双指针-合并区间

描述:
给出一组区间,请合并所有重叠的区间。
请保证合并后的区间按区间起点升序排列。

数据范围:区间组数 0≤n≤2×10^5,区间内 的值都满足 0≤val≤2×10^5

要求:空间复杂度 O(n)O(n),时间复杂度 O(nlogn)O(nlogn)
进阶:空间复杂度 O(val)O(val),时间复杂度O(val)O(val)

import java.util.*;
/**
 * Definition for an interval.
 * public class Interval {
 *     int start;
 *     int end;
 *     Interval() { start = 0; end = 0; }
 *     Interval(int s, int e) { start = s; end = e; }
 * }
 */
public class Solution {
    public ArrayList<Interval> merge(ArrayList<Interval> intervals) {
        ArrayList<Interval> res = new ArrayList<>();
        //去除特殊情况
        if(intervals.size() == 0){
            return res;
        }

        Collections.sort(intervals, new Comparator<Interval>(){
            public int compare(Interval o1, Interval o2){
                if(o1.start != o2.start)
                    return o1.start - o2.start;
                else
                    return o1.end - o2.end;
            }
        });

        //放入第一个区间
        res.add(intervals.get(0));
        int count = 0;
        //遍历后续区间,查看是否与末尾有重叠
        for(int i = 1; i < intervals.size(); i++){
            Interval o1 = intervals.get(i);
            Interval origin = res.get(count);
            if(o1.start > origin.end){
                res.add(o1);
                count++;
            //区间有重叠,更新结尾
            }else{
                res.remove(count);
                Interval s = new Interval(origin.start, o1.end);
                if(o1.end < origin.end)
                    s.end = origin.end;
                res.add(s);
            }
        }
        return res;
    }

  
}

双指针-最小覆盖子串

描述:
给出两个字符串 s 和 t,要求在 s 中找出最短的包含 t 中所有字符的连续子串。

数据范围:0≤∣S∣,∣T∣≤10000,保证s和t字符串中仅包含大小写英文字母

例如:
S ="XDOYEZODEYXNZ"S=“XDOYEZODEYXNZ”
T =“XYZ"T=“XYZ”
找出的最短子串为"YXNZ”“YXNZ”.

注意:
如果 s 中没有包含 t 中所有字符的子串,返回空字符串 “”;
满足条件的子串可能有很多,但是题目保证满足条件的最短的子串唯一。

示例1

输入:
“XDOYEZODEYXNZ”,“XYZ”

返回值:
“YXNZ”

import java.util.*;


public class Solution {
    /**
     * 
     * @param S string字符串 
     * @param T string字符串 
     * @return string字符串
     */
    public String minWindow (String S, String T) {
        // 定义边界排序特殊情况
        if(S.length() == 0 || T.length() == 0) {
        return "" ;
        }
        // hash初始化
        int minCount = Integer.MAX_VALUE ;
        int[] hash = new int[128] ;
        for(int i = 0 ; i < T.length() ; i ++) {
            hash[T.charAt(i)] -- ;
        }
        int minLen = Integer.MAX_VALUE ;//记录最小覆盖子串的长度
        int ri = 0 ;//记录最小覆盖子串的左边界
        int rj = 0 ;//记录最小覆盖子串的右边界
        int f = 0 ;//窗口右边界
        int s = 0 ;//窗口左边界
        while(f < S.length()) {//右边界向右移动
            hash[S.charAt(f)]++ ;//将当前右边界坐对对应的字符加入hash
            while(s <= f && check(hash)) {//如果已经覆盖了,则不断让左边界右移,寻找最短的满足要求的子串
                if(f - s + 1 < minLen) {//更新小覆盖子串的记录
                    minLen = f - s + 1 ;
                    ri = s ;
                    rj = f ;
                }
                hash[S.charAt(s)] -- ;//将左边界移除hash
                s ++ ;//左边界右移
            }
            f ++ ;//右边界右移
        }
        if(f - s + 1 > S.length()) {//如果右边界超出S时左边界都没动过,说明不存在覆盖子串
            return "" ;
        } else {//截取
            return S.substring(ri , rj + 1) ;
        }
    }

      //检查是否有小于0的
    boolean check(int[] hash) {
        for (int i = 0; i < hash.length; i++) {
            if (hash[i] < 0)
                return false;
        }
        return true;
    };
}

双指针-反转字符串

描述:
写出一个程序,接受一个字符串,然后输出该字符串反转后的字符串。(字符串长度不超过1000)

数据范围: 0≤n≤1000
要求:空间复杂度 O(n)O(n),时间复杂度 O(n)O(n)

示例1

输入:
“abcd”

返回值:
“dcba”

import java.util.*;


public class Solution {
    /**
     * 反转字符串
     * @param str string字符串 
     * @return string字符串
     */
    public String solve (String str) {
        // write code here
        char[] ans = str.toCharArray();
        int len = str.length();
        for(int i = 0 ; i < len ;i++){
                ans[i] = str.charAt(len-1-i);
        }
        return new String(ans);
    }
}

双指针-最长无重复子数组

描述:
给定一个长度为n的数组arr,返回arr的最长无重复元素子数组的长度,无重复指的是所有数字都不相同。
子数组是连续的,比如[1,3,5,7,9]的子数组有[1,3],[3,5,7]等等,但是[1,3,7]不是子数组

示例1

输入:
[1,2,3,1,2,3,2,2]

返回值:
3

说明:
最长子数组为[1,2,3]

解法一,双指针方法

import java.util.*;


public class Solution {
    /**
     * 
     * @param arr int整型一维数组 the array
     * @return int整型
     */
    public int maxLength (int[] arr) {
        // write code here
        if (arr.length == 0){
            return 0;
        }
        HashMap<Integer, Integer> map = new HashMap<>();
        int max = 0;
        for (int i = 0, j = 0; i < arr.length; ++i) {
            if (map.containsKey(arr[i])) {
                j = Math.max(j, map.get(arr[i]) + 1);
            }
            map.put(arr[i], i);
            max = Math.max(max, i - j + 1);
        }
        return max;
    }
}

解法二,队列

import java.util.*;


public class Solution {
    /**
     * 
     * @param arr int整型一维数组 the array
     * @return int整型
     */
    public int maxLength (int[] arr) {
    //用链表实现队列,队列是先进先出的
        Queue<Integer> queue = new LinkedList<>();
        int res = 0;
        for (int c : arr) {
            while (queue.contains(c)) {
                //如果有重复的,队头出队
                queue.poll();
            }
            //添加到队尾
            queue.add(c);
            res = Math.max(res, queue.size());
        }
        return res;
    }
}

解法三,set集合

import java.util.*;


public class Solution {
 /**
  * 
  * @param arr int整型一维数组 the array
  * @return int整型
  */
 public int maxLength (int[] arr) {
     int left = 0, right = 0, max = 0;
     Set<Integer> set = new HashSet<>();
     while (right < arr.length) {
 		// 有重复的,直接删除前面的数字
         if (set.contains(arr[right])) {
             set.remove(arr[left++]);
         } else {
             set.add(arr[right++]);
             max = Math.max(max, set.size());
         }
     }
     return max;
 }
}

双指针-盛水最多的容器

描述:
给定一个数组height,长度为n,每个数代表坐标轴中的一个点的高度,height[i]是在第i点的高度,请问,从中选2个高度与x轴组成的容器最多能容纳多少水
1.你不能倾斜容器
2.当n小于2时,视为不能形成容器,请返回0
3.数据保证能容纳最多的水不会超过整形范围,即不会超过2^31-1

数据范围:
0<=height.length<=10^5
0<=height[i]<=10^4

示例1

输入:
[1,7,3,2,4,5,8,2,7]

返回值:
49

解法一,双指针两边同时移动

import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param height int整型一维数组 
     * @return int整型
     */
    public int maxArea (int[] height) {
        int i = 0, j = height.length - 1;
        int h = 1, max = 0;
        while (i < j) {
            if (height[i] < h) { // 左板不达标
                i++;
            } else if (height[j] < h) { // 右板不达标
                 j--;
            } else {
            max = Math.max(h++ * (j - i), max); // 记录水高度为h时的最大盛水量
         }
        }
    return max;
    }
}

解法二,双指针两边同时移动

import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param height int整型一维数组 
     * @return int整型
     */
    public int maxArea (int[] height) {
        // write code here
        int left =0,right = height.length-1;
        int max = 0;
        while(left<right){
            if(height[left]<height[right]){
                max = Math.max(max,(height[left]*(right-left)));
                left++;
            }else {
                max = Math.max(max,(height[right]*(right-left)));
                right--;
            }
        }
        return max;
    }
}

双指针-接雨水问题

描述:
给定一个整形数组arr,已知其中所有的值都是非负的,将这个数组看作一个柱子高度图,计算按此排列的柱子,下雨之后能接多少雨水。(数组以外的区域高度视为0)

数据范围:数组长度 0≤n≤2×10^5,数组中每个值满足 0<val≤10^9 ,保证返回结果满足 0≤val≤10^9

要求:时间复杂度 O(n)O(n)

import java.util.*;


public class Solution {
    /**
     * max water
     * @param arr int整型一维数组 the array
     * @return long长整型
     */
    public long maxWater (int[] arr) {
        //排除空数组
        if(arr.length == 0)
            return 0;
        long res = 0;
        //左右双指针
        int left = 0;
        int right = arr.length - 1;
        //中间区域的边界高度
        int maxL = 0;
        int maxR = 0;
        //直到左右指针相遇
        while(left < right){
            //每次维护往中间的最大边界
            maxL = Math.max(maxL, arr[left]);
            maxR = Math.max(maxR, arr[right]);
            //较短的边界确定该格子的水量
            if(maxR > maxL)
                res += maxL - arr[left++];
            else
                res += maxR - arr[right--];
        }
        return res;
    }
}
  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 中文翻译:双指针算法是一种非常有用的算法,它可以在需要处理数组和字符串的编程任务中发挥重要作用。它的思想是通过使用两个指针,一个指针指向数组或字符串的头部,另一个指针指向尾部,然后以某种方式移动它们,从而实现指定的任务。 ### 回答2: 双指针算法是一种常用的算法思想,在Java语言中也常常使用。该算法的主要思想是使用两个指针分别指向数组或链表的不同位置,从而解决一些特定类型的问题。 双指针算法包括了两种常见的应用场景:快慢指针和左右指针。 1. 快慢指针:快慢指针一般用于解决链表中的问题。快指针一次移动多步,慢指针一次只移动一步。通过快慢指针的移动,可以判断链表是否有环、找到链表的中间节点等。 以判断链表是否有环为例,可以使用快慢指针来解决。定义两个指针,一个快指针每次移动两步,一个慢指针每次移动一步。如果链表中存在环,则快指针和慢指针最终会相遇;如果链表中不存在环,则快指针会先到达链表尾部。 2. 左右指针:左右指针一般用于解决数组或字符串的问题。左指针从数组的起始位置开始,右指针从数组的结束位置开始。通过左右指针的移动,可以实现数组中元素的遍历、查找、翻转等操作。 以数组中两数之和为目标值的问题为例,可以使用左右指针来解决。在已排序的数组中,定义左指针指向数组的起始位置,右指针指向数组的结束位置。比较左右指针所指向的元素之和与目标值的大小关系,根据不同的情况移动左指针或右指针,直到找到目标值或者左指针遇到右指针。 以上就是Java中双指针算法的简单介绍。双指针算法能够通过两个指针的协同工作,高效解决一些问题,提高算法的时间和空间效率。在实际开发中,根据问题的特性选择不同的双指针算法,可以有效地提高算法的效率。 ### 回答3: 双指针算法是一种常用于数组或链表问题的解决方法,它使用两个指针来在同一数据结构上进行迭代和比较。Java中双指针算法的写法如下: 首先,确定双指针的初始位置。 通常情况下,我们将一个指针称为慢指针(slow),另一个指针称为快指针(fast)。它们的初始位置可以是数组/链表的头部(0)或者其他合适的位置,具体取决于问题的要求。 接下来,通过移动指针来解决问题。 在双指针算法中,我们需要根据实际情况决定如何移动快慢指针。通常有以下几种情况: 1. 快慢指针向同一个方向移动,通常用于寻找某种特定条件的满足情况。此时,我们可以通过修改指针的步长来控制指针的移动,比如慢指针每次移动1步,快指针每次移动2步。 2. 快慢指针向相反方向移动,通常用于查找数组或链表中的两个元素之间的关系。在这种情况下,我们可以使用两层循环来遍历所有可能的组合。 3. 快慢指针向相同方向移动,直到满足某种条件为止。在该情况下,我们可以通过比较两个指针指向的元素来判断是否满足条件。如果满足条件,则将指向元素的指针向前移动一步;否则将另一个指针向前移动一步。 最后,根据问题的要求返回结果。 根据问题的不同,我们可以在移动指针的过程中判断并返回特定的值。或者,我们也可以使用快慢指针来重新排列数组或链表,以满足特定的要求。 综上所述,双指针算法是一种高效的解决数组或链表问题的方法,可以通过移动指针、比较指向元素来解决不同类型的问题。通过灵活运用双指针算法,可以得到简洁、高效的解决方案。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值