双指针总结
- 532. 数组中的 k-diff 数对(前后指针)
- 925. 长按键入
- 56. 合并区间
- 75. 颜色分类
- 80. 删除有序数组中的重复项 II&26. 删除有序数组中的重复项(快慢指针&套路魔板题型)
- 485. 最大连续 1 的个数(可变滑动窗口魔板)
- 11. 盛最多水的容器
- 26. 删除有序数组中的重复项
- 27. 移除元素
- 125. 验证回文串
- 238. 除自身以外数组的乘积
- 448. 找到所有数组中消失的数字(原地哈希)
- 442. 数组中重复的数据(原地哈希,和448一致)
- 1480. 一维数组的动态和(快慢指针,原地修改数组)
- 42. 接雨水(三指针+双指针)
- 15. 三数之和(排序+双指针)
- 18. 四数之和(排序+双指针)
- 167. 两数之和 II - 输入有序数组(双指针)
- 350. 两个数组的交集 II(双指针)
常见双指针算法分为三类,同向(即两个指针都相同一个方向移动),背向(两个指针从相同或者相邻的位置出发,背向移动直到其中一根指针到达边界为止),相向(两个指针从两边出发一起向中间移动直到两个指针相遇)
532. 数组中的 k-diff 数对(前后指针)
class Solution {
public int findPairs(int[] nums, int k) {
/**
分析:
题意中是要返回不同数对的数量,那么(1,2)和(2,1)其实本质是一样的,这里规定从小到大排序,即数对是非严格递增的==》将数组排好序,利用双指针特性,在合适的时候,进行前后指针的移动
*/
Arrays.sort(nums);
int len = nums.length;
if(len < 2){
// 只有一个数,不会构成数对
return 0;
}
// 结果
int res = 0;
// 至少是两个数
int left = 0;
int right = 1;
while(left <= right && right < len){
if(nums[right] - nums[left] == k){
// 找到数对
res++;
// 下面的逻辑是解题的关键!!!
// 移动右指针并判断指针数与前一个数是否重合
do{
right++;
}while(right < len && nums[right] == nums[right-1]);
// 移动左指针并判断指针值与前一个数是否重合
do{
left++;
}while(left < right &&nums[left] == nums[left - 1]);
}else if(nums[right] - nums[left] > k){
// 移动左指针
left++;
}else{
// 移动右指针
right++;
}
// 两个指针必须对应数组中的两个数
if(left == right){
// 两指针重合,右指针走一步
right++;
}
}
return res;
}
}
注意:这种题目还可以用哈希表,在使用哈希表过程中要时刻保持对HashMap和HashSet的敏感度,其中HashMap的使用,有些储存的是值-下标,有些储存的是值-个数,有些储存的是值-值。根据题目,灵活使用!
class Solution {
public int findPairs(int[] nums, int k) {
/*
这道题其实很像two-sum的变种题,一看到两数相加等于一个target,第一个想法就是哈希表,唯一不同的点就在于,这里数对的定义(1,2)和(2,1)是同一个数对,所以核心思路就是如何去去重==》数组预先排序,定义一个储存数对的哈希表和储存遍历元素的哈希表
注意:这里是对HashSet的使用,扩充了去除重复元素的思路。
*/
Arrays.sort(nums);
// 储存数对的哈希表
Map<Integer,Integer> map = new HashMap<>();
// 储存遍历元素的哈希表
Set<Integer> set = new HashSet<>();
// 遍历元素
for(int i = 0; i < nums.length; i++){
if(set.contains(nums[i] - k)){
// set中有遍历元素,那么储存数对
map.put(nums[i],nums[i] - k);
}
// 储存遍历元素,比如有n个1,最后set中只会有一个1,达到去重目的
set.add(nums[i]);
}
// map的大小就是数对中的个数
return map.size();
}
}
925. 长按键入
class Solution {
public boolean isLongPressedName(String name, String typed) {
/**
分析:
题目的意思就是name中的一个字母可能对应typed中多个相同字母,那么这里就可以使用个一个计数变量count,当count>0时,说name中的字母出现的次数比typed中字母出现的次数还要高,就直接返回false。
当遍历完name后,若发现还没有遍历完typed,则发现typed中存在多余的字符,这时候,也是返回false,反之返回true
*/
// 特判
if(name.length() == 0 || typed.length() == 0){
return false;
}
int i = 0;
int j = 0;
while( i < name.length()){
// 定义一个计数变量count
int count = 0;
// 定义字符ch
char ch = name.charAt(i);
// 遍历name中所有ch字符
while( i < name.length() && name.charAt(i) == ch){
// 找到ch字符,+1
count++;
// 移动指针
i++;
}
// 遍历typed中所有ch字符
while( j < typed.length() && typed.charAt(j) == ch){
// 找到ch字符,-1
count--;
// 移动指针
j++;
}
// 在本轮侦查过程中,发现count>0,则返回false
if(count > 0){
return false;
}
}
// 遍历完name后,发现j不等于typed的长度,则返回false
return j == typed.length();
}
}
56. 合并区间
class Solution {
public int[][] merge(int[][] intervals) {
/**
分析:
第一想法就是对二维数组排好序,定义结果数组,对原始数组单层循环遍历,根据条件判断是否应该合并。
第一次解法的误区就是没有定义好双指针,当发生合并时,指针没有及时更新。
还有就是对最后一组数组要进行添加。
*/
if(intervals.length == 1){
return intervals;
}
// 定义结果数组和区间个数count
int[][] res = new int[intervals.length][2];
int count = 0;
// 对二维数组进行排序
Arrays.sort(intervals,(a,b) -> {return a[0] - b[0];});
// 定义初始双指针
int start = intervals[0][0],end = intervals[0][1];
// 遍历数组,从第二组开始
for(int i = 1; i < intervals.length; i++){
// 后一组区间的下界比end小
if(intervals[i][0] <= end){
// 更新指针的end界限
end = Math.max(end,intervals[i][1]);
}else{
// 合并区间
res[count][0] = start;
res[count][1] = end;
count++;
// 双指针指向新区间
start = intervals[i][0];
end = intervals[i][1];
}
}
// 添加最后一组数据
res[count][0] = start;
res[count][1] = end;
count++;
// 截取二维数组
return Arrays.copyOfRange(res,0,count);
}
}
75. 颜色分类
class Solution {
public void sortColors(int[] nums) {
//计数排序,时间复杂度为O(m+n)
int[] color = new int[3];
for(int num:nums) {
color[num]++; //将颜色叠加,储存个数
}
int k=0;
for(int j=0;j<3;j++) {
while(color[j]--!=0) {
// 依次输出个数
nums[k++]=j;
}
}
}
}
80. 删除有序数组中的重复项 II&26. 删除有序数组中的重复项(快慢指针&套路魔板题型)
class Solution {
public int removeDuplicates(int[] nums) {
/**
分析;
这一题和26题是一模一样,只不过这里元素最多出现2次。
使用方法依旧是快慢指针原地修改数组.
慢指针用来原地修改数组,只有满足特定条件,慢指针才会走
快指针用来遍历
*/
int len = nums.length;
if(len <= 2){
return len;
}
// 定义快慢指针
int slow = 2;
int fast = 2;
while(fast < len){
// 当nums[slow-2] != nums[fast],意味着fast是符合题意的
if(nums[slow - 2] != nums[fast]){
// 原地修改数组
nums[slow] = nums[fast];
// 移动慢指针
slow++;
}
// 快指针移动
fast++;
}
// 最后返回慢指针,就是个数了
return slow;
}
}
注意:这里的核心在于考虑清楚nums[slow-2] = nums[fast]时,那么num[slow-2]=nums[slow-1]=nums[fast]必然存在!
class Solution {
public int removeDuplicates(int[] nums) {
return process(nums, 2);
}
int process(int[] nums, int k) {
int u = 0;
for (int x : nums) {
if (u < k || nums[u - k] != x) nums[u++] = x;
}
return u;
}
}
注意:这里的核心在于保留k个数,同时判别前k个数是否与当前数相等,其实本质和快慢指针是一样一样的,只不过这里将其泛化了,更有通用性
485. 最大连续 1 的个数(可变滑动窗口魔板)
class Solution {
public int findMaxConsecutiveOnes(int[] nums) {
/**
分析:
这是一个求解最大连续数组问题,因此立刻就想到滑动窗口。
每次记录更新窗口的最大值。
可变滑动窗口解题魔板:
l 和 r 都初始化为 0
r 指针移动一步
判断窗口内的连续元素是否满足题目限定的条件
如果满足,再判断是否需要更新最优解,如果需要则更新最优解。并尝试通过移动 l 指针缩小窗口大小。循环执行,如果不满足,则继续。
形象地来看的话,就是 r 指针不停向右移动,l 指针仅仅在窗口满足条件之后才会移动,起到窗口收缩的效果。
*/
int len = nums.length;
int left = 0;
int right = 0;
int count = 0;
while(left <= right && right < len){
// 遇到0,就要更新个数,这时候就要缩小窗口了
if(nums[right] == 0){
// 更新个数
count = Math.max(count,right - left );
// 保证left和right又指向同一个数,继续探寻count
left = right + 1;
}
// 右指针移动
right++;
}
// 处理数组最后一组1,取最大值
count = Math.max(count,len - left );
return count;
}
}
注意:本题一定要掌握滑动窗口的判别,求解连续子数组问题!!!同时牢记滑动窗口魔板,定义left和right指针为0,right指针一直走,在特点条件下,缩小滑动窗口,更新left指针(这里要根据题目实际场景!),然后使用Math函数,实时更新窗口的最大最小值,最后别忘记处理末尾一组数据!
11. 盛最多水的容器
暴力法结果时间超时,所以要优化思路,采用双指针法!
class Solution {
public int maxArea(int[] height) {
/**
分析:容纳最多的水等价于横坐标之间的距离乘以高
暴力法:遍历,最后显示时间超时!算法需要优化
*/
int n = height.length;
int ans = 0;
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
int area = Math.min(height[i], height[j]) * (j - i);
ans = Math.max(ans, area);
}
}
return ans;
}
}
本题中核心就是理解面积的增大最有可能在于短板的提升,移动长板是不会增大面积的(因为面积在于短板高度,移动指针后,两指针指针的距离就又减少的),时间复杂度为O(n)
class Solution {
public int maxArea(int[] height) {
/**
本题中核心就是理解面积的增大最有可能在于短板的提升,移动长板是不会增大面积的(因为面积在于短板高度,移动指针后,两指针指针的距离就又减少的)
双指针:左右双指针法,在特定条件下移动指针
*/
int left = 0;
int right = height.length - 1;
// 定义结果
int res = 0;
while(left < right){
// 寻找短板,移动短板
if(height[left] < height[right]){
res = Math.max(res,(right - left) * height[left] );
// left是短板
left++;
}else{
res = Math.max(res,(right - left) * height[right] );
// right是短板
right--;
}
}
return res;
}
}
26. 删除有序数组中的重复项
注意:原地修改数组,第一想法就要想到快慢指针!!!
class Solution {
public int removeDuplicates(int[] nums) {
/**
分析:
数组已经有序,并且是原地修改数组(原地修改数组首先就应该想到用快慢指针法)
快指针一直移动,慢指针只有在特定情况下移动
*/
int fast = 0;
int slow = 0;
while(fast < nums.length){
if(nums[slow] != nums[fast]){
// 两者不相等的时候,慢指针移动了
nums[++slow] = nums[fast];
}
// 快指针一直移动
fast++;
}
return slow+1;
}
}
27. 移除元素
class Solution {
public int removeElement(int[] nums, int val) {
/**
原地移除特定数值(其实就是原地修改数组)==》快慢指针法
*/
// 特判
if(nums.length == 0){
return 0;
}
int fast = 0;
int slow= 0;
while(fast < nums.length){
if(nums[fast] != val){
nums[slow++] = nums[fast];
}
// 快指针移动
fast++;
}
return slow;
}
}
125. 验证回文串
class Solution {
public boolean isPalindrome(String s) {
/**
分析:
判断回文串很明显使用双指针==》对撞指针法
回文串的判别只考虑字母(忽略字母大小写)和数字字符==》遍历字符串存入数组中!
本题更多考察的是api的使用:
- 字符是否为字母:Character.isLetter()
- 字符是否为数字:Character.isDigit()
- 字符是否为字母或者数字:Character.isLetterOrDigit()
- 字符转化为小写:Character.toLowerCase()
- 字符转化为大写:Character.toUpperCase()
*/
int len = s.length() - 1;
int left = 0, right = len;
while(left < right){
// 忽略左边无效字符
while( left < right && !Character.isLetterOrDigit(s.charAt(left))){
left++;
}
// 忽略右边无效字符
while( left < right && !Character.isLetterOrDigit(s.charAt(right))){
right--;
}
// 统一成小写字母进行回文验证
if(Character.toLowerCase(s.charAt(left)) != Character.toLowerCase(s.charAt(right))){
return false;
}
left++;
right--;
}
return true;
}
}
238. 除自身以外数组的乘积
class Solution {
public int[] productExceptSelf(int[] nums) {
/**
分析:
一般思路是遍历数组,将所有数字乘积,然后除以索引上的数字(如果遇到索引上的数字为0,则失效),题目也规定了不能采用该方法。
那么可以考虑乘积列表法,将该索引左边的乘积和右边的乘积再次相乘最后可以得到答案!
*/
// 定义左右乘积数组
int len = nums.length;
int[] left = new int[len];
int[] right = new int[len];
// 遍历数组
// left[0] 初始化为1
left[0] = 1;
for(int i = 1; i < len; i++){
left[i] = left[i - 1] * nums[i - 1];
}
// right[len - 1] 初始化为1
right[len - 1] = 1;
for(int i = len -2; i >= 0; i--){
right[i] = right[i + 1] * nums[i + 1];
}
int[] res = new int[len];
// 最后左右乘积数组再次相乘
for(int i = 0; i < len; i++){
res[i] = left[i] * right[i];
}
return res;
}
}
注意:本题带给我的收获是分治的思想,一次性算不出来,那么分两次(左边两边存储起来~)很多题目都用到了这种思想!!!
448. 找到所有数组中消失的数字(原地哈希)
注意:第一种方法是常规的使用哈希表法
class Solution {
public List<Integer> findDisappearedNumbers(int[] nums) {
/**
分析:
将1-n储存到哈希表中,遍历数组,如果存在则移除哈希表对应值,最后返回哈希表中余下的个数
*/
Set<Integer> set = new HashSet<>();
List<Integer> res = new ArrayList<>();
int n = nums.length;
// [1,n]添加到哈希表中
for(int i = 1; i <= n; i++){
set.add(i);
}
for(int i = 0; i < n; i++){
if(set.contains(nums[i])){
// 移除哈希表
set.remove(nums[i]);
}
}
// 添加剩下的元素
for(Integer i: set){
res.add(i);
}
return res;
}
}
注意:第二种方法使用的是原地哈希法!很巧妙,关键是理解数组nums[i]为[1,n],而数组的下标是[0,n-1],先将数组“排好序”
class Solution {
public List<Integer> findDisappearedNumbers(int[] nums) {
/**
分析:
思考:
数组nums[i]为[1,n],而数组的下标是[0,n-1],可以考虑原地哈希!
按照正常逻辑来说,如果数组是排好序的,那么下标与数组值nums[i]的关系是下标i+1 = nums[i]。
相等的话,index++,对下一个数进行位置寻找,如果不相等,就将数字放到正确的位置中(这里又有两种情况:1正确位置的值与当前位置的值相等,ok,index++,continue循环2正确为值的与当前位置的值不相等,ok,交换两个空间,并且保持index不变对当前index继续探索)
最后遍历“排好序的数组”,若发现index+1不等于当前数组值,则就是缺失的元素(index+1)。
*/
int len = nums.length;
int index = 0;
while(index < len){
// 遍历数组,探寻数组正确位置
if(nums[index] == index + 1){
// index+1 和当前值一致,“这个排好序了”,index++
index++;
}else{
// 不一致,那么继续探索正确位置
int targetIndex = nums[index] - 1;
if(nums[targetIndex] == nums[index]){
// 若探索到的位置值和当前的值一样(重复元素),那么index++,跳过当前循环
index++;
continue;
}
// 和当前位置不一致,那么就可以进行交换,交换后继续探索当前index的正确位置
int temp = nums[targetIndex];
nums[targetIndex] = nums[index];
nums[index] = temp;
}
}
List<Integer> res = new ArrayList<>();
// 遍历“排好序的数组”
for(int i = 0; i < len; i++){
// 发现“排序好数组中”下标+1不等于当前值,说明该数是重复的元素
if( i + 1 != nums[i] ){
// 添加缺失的元素 i + 1
res.add(i + 1);
}
}
return res;
}
}
442. 数组中重复的数据(原地哈希,和448一致)
class Solution {
public List<Integer> findDuplicates(int[] nums) {
/**
分析:
数组中的元素只有两种情况:出现一次或者出现两次
重复问题的==》哈希表
题目规定不使用额外空间==》。。。
*/
Set<Integer> set = new HashSet<>();
List<Integer> res = new ArrayList<>();
for(int i = 0; i < nums.length; i++){
if(set.contains(nums[i])){
res.add(nums[i]);
}
// 添加到哈希表中
set.add(nums[i]);
}
return res;
}
}
class Solution {
public List<Integer> findDuplicates(int[] nums) {
/**
本题思路和448题思路一致,依旧使用原地哈希的思想(数组nums[i]值为[1,n],下标为[0,n-1])。
那么就把数组“排好序”,正确的位置中num[i] == i + 1,错误位置就是出现两次的元素了!
*/
int len = nums.length;
int index = 0;
while(index < len){
if(nums[index] == index+1){
index++;
}else{
int targetIndex = nums[index] - 1;
if(nums[targetIndex] == nums[index]){
index++;
continue;
}
int temp = nums[targetIndex];
nums[targetIndex] = nums[index];
nums[index] = temp;
}
}
List<Integer> res = new ArrayList<>();
for(int i = 0; i <len; i++){
if(i+1 != nums[i]){
res.add(nums[i]);
}
}
return res;
}
}
1480. 一维数组的动态和(快慢指针,原地修改数组)
class Solution {
public int[] runningSum(int[] nums) {
/**
分析:
本题可以使用原地修改数组的方法(快慢指针法),降低时间复杂度
*/
if(nums.length < 2){
return nums;
}
int slow = 0;
int fast = 1;
while(fast < nums.length){
nums[fast] = nums[slow] + nums[fast];
fast++;
slow++;
}
return nums;
}
}
42. 接雨水(三指针+双指针)
三指针
class Solution {
public int trap(int[] height) {
/**
分析:
参考视频题解
https://www.bilibili.com/video/av375531574/
运用双指针,不断找出U型结构,其中U型结构可以是左边低,右边高和左边高,右边低的两种类型
参考文字题解:
https://leetcode-cn.com/problems/trapping-rain-water/solution/shuang-zhi-zhen-qiu-jie-yu-shui-wen-ti-t-ojil/
解法一:三指针法,找到最大高度,top指针指向。top区域左右两边分别使用双指针求解。
top左边区域,根据木桶效应,必须是left > right,才有雨水(这里的left和right代表高度)
此时的雨水 为 res += left - right,否则 left = right
右边区域同理,只不过是right - left(木桶效应)
*/
// 寻找最大高度的值和下标
int maxValue = 0;
int maxIndex = 0;
for(int i = 0; i < height.length; i++){
if(height[i] > maxValue){
maxValue = height[i];
maxIndex = i;
}
}
int left = height[0];
int right = 0;
int sum = 0;
// 最大下标的左边区域
for(int i = 1; i < maxIndex; i++){
right = height[i];
if(right > left){
left = right;
}else{
sum += left - right;
}
}
right = height[height.length - 1];
// 最大下标的右边区域
for(int i = height.length - 2; i > maxIndex; i--){
left = height[i];
if(right < left){
right = left;
}else{
sum += right - left;
}
}
return sum;
}
}
双指针
class Solution {
public int trap(int[] height) {
// 使用双指针法
int left = 0, right = height.length - 1;
// 定义左边区域的最大高 和右边区域的最大高
int leftMax = 0, rightMax = 0;
int res = 0;
while(left < right){
leftMax = Math.max(leftMax,height[left]);
rightMax = Math.max(rightMax,height[right]);
// 若是height[left] <= height[right]就会出现 左低右高的U形结构,必有雨水
if(height[left] <= height[right]){
// 雨水等于 左边最大高 - 当前左边高
res += leftMax - height[left];
// 移动左边
left++;
}else{
res += rightMax - height[right];
right--;
}
}
return res;
}
}
15. 三数之和(排序+双指针)
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
/**
分析:
第一想法是暴力法,三重for循环,结果时间超时了
第二想法是排序+双指针法,a+b+c = 0,可以看做是a+b = -c
*/
// 暴力法 时间超时
// if(nums.length < 3){
// return new ArrayList<>();
// }
// // 定义结果,这里使用了hashset去重
// Set<List<Integer>> res = new HashSet<>();
// // 数组排序
// Arrays.sort(nums);
// // 遍历
// for(int i = 0; i < nums.length; i++){
// for(int j = i + 1; j < nums.length; j++){
// for(int k = j + 1; k < nums.length; k++){
// if(nums[i] + nums[j] + nums[k] == 0){
// res.add(Arrays.asList(nums[i],nums[j],nums[k]));
// }
// }
// }
// }
// return new ArrayList<>(res);
// 使用排序+双指针法
if(nums.length < 3){
return new ArrayList<>();
}
Set<List<Integer>> res = new HashSet<>();
Arrays.sort(nums);
for(int i = 0; i < nums.length; i++){
int target = - nums[i];
// 从 i + 1后面搜索 两数和为 target ,这里使用二分查找
int left = i + 1;
int right = nums.length - 1;
while(left < right){
int sum = nums[left] + nums[right];
if( sum == target){
res.add(Arrays.asList(nums[i],nums[left],nums[right]));
// 下面的循环是为了去重
while(left < right && nums[left] == nums[++left]){
}
while(left < right && nums[right] == nums[--right]){
}
}else if(sum > target){
right--;
}else{
left++;
}
}
}
return new ArrayList<>(res);
}
}
18. 四数之和(排序+双指针)
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
/**
分析:
排序+双指针
四数之和可以拆成 两数之和的等价形式
*/
// 使用set进行去重 后来发现使用条件语句去重效率更高!
// Set<List<Integer>> res = new HashSet<>();
List<List<Integer>> res = new ArrayList<>();
// 排序
Arrays.sort(nums);
for(int i = 0; i < nums.length; i++){
// 使用条件语句去重
if( i > 0 && nums[i] == nums[i - 1]){
continue;
}
for(int j = i + 1; j < nums.length; j++){
// 使用条件语句去重
if( j > i + 1 && nums[j] == nums[j - 1]){
continue;
}
// 定义部分和
int partSum = nums[i] + nums[j];
// 定义双指针
int left = j + 1;
int right = nums.length - 1;
while(left < right){
int sum = partSum + nums[left] + nums[right];
if(sum == target){
res.add(Arrays.asList(nums[i],nums[j],nums[left],nums[right]));
// 去重
while( left < right && nums[left] == nums[++left]);
while( left < right && nums[right] == nums[--right]);
}else if(sum > target){
right--;
}else{
left++;
}
}
}
}
return res;
}
}
167. 两数之和 II - 输入有序数组(双指针)
class Solution {
public int[] twoSum(int[] numbers, int target) {
// Map<Integer,Integer> map = new HashMap<>();
// for(int i = 0; i < numbers.length; i++){
// if(map.containsKey(target - numbers[i])){
// // 这里注意返回的次序
// return new int[]{map.get(target-numbers[i]) + 1,i+1};
// }
// // 储存
// map.put(numbers[i],i);
// }
// return null;
// 使用双指针法,这个其实不算二分查找,其实核心思想是理解缩小搜索空间,变为o(n)
int len = numbers.length;
int left = 0;
int right = len - 1;
// 题目要求,不可以重复使用元素
while(left < right) {
int sum = numbers[left] + numbers[right];
if(sum < target){
// 说明sum要加大
left++;
}else if(sum > target){
// 说明sum要减小
right--;
}else{
// 相等情况
return new int[]{left+1,right+1};
}
}
return null;
}
}
350. 两个数组的交集 II(双指针)
class Solution {
public int[] intersect(int[] nums1, int[] nums2) {
// 先排序,在使用双指针法,本题解答很像167. 两数之和 II - 输入有序数组]的双指针解法
Arrays.sort(nums1);
Arrays.sort(nums2);
// 定义结果解
int[] res = new int[nums1.length];
// 结果个数
int count = 0;
// 双指针,对应两个数组
int p1,p2;
p1 = p2 = 0;
// 但凡有一个指针走到尽头直接over
while(p1 < nums1.length && p2 < nums2.length){
if(nums1[p1] > nums2[p2]){
// p2该努力啦~
p2++;
}else if(nums1[p1] < nums2[p2]){
// p1 该努力啦!
p1++;
}else{
// 匹配成功,两个都一起努力走~
res[count++] = nums1[p1];
p1++;
p2++;
}
}
// 调用Arrays类方法截取数据
return Arrays.copyOfRange(res,0,count);
}
}