算法-双指针(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(iB,B先放
                res[r++] = B[j++];
            }
        }
        //如果A,B其中有一个遍历完,另一个没遍历完,则将未遍历完的数组中的元素全部加入res中
        while(i

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

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

数据范围:0 要求:空间复杂度 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 merge(ArrayList intervals) {
        ArrayList res = new ArrayList<>();
        //去除特殊情况
        if(intervals.size() == 0){
            return res;
        }

        Collections.sort(intervals, new Comparator(){
            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 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 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 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

双指针-接雨水问题

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

数据范围:数组长度 0≤n≤2×10^5,数组中每个值满足 0

要求:时间复杂度 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;
    }
}

你可能感兴趣的:(算法,算法,java,数据结构)