java数组:移除元素 双指针法

27.移除元素

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素。元素的顺序可能发生改变。然后返回 nums 中与 val 不同的元素的数量。

假设 nums 中不等于 val 的元素数量为 k,要通过此题,您需要执行以下操作:

  • 更改 nums 数组,使 nums 的前 k 个元素包含不等于 val 的元素。nums 的其余元素和 nums 的大小并不重要。
  • 返回 k

用户评测:

评测机将使用以下代码测试您的解决方案:

int[] nums = [...]; // 输入数组
int val = ...; // 要移除的值
int[] expectedNums = [...]; // 长度正确的预期答案。
                            // 它以不等于 val 的值排序。

int k = removeElement(nums, val); // 调用你的实现

assert k == expectedNums.length;
sort(nums, 0, k); // 排序 nums 的前 k 个元素
for (int i = 0; i < actualLength; i++) {
    assert nums[i] == expectedNums[i];
}

如果所有的断言都通过,你的解决方案将会 通过

示例 1:

输入:nums = [3,2,2,3], val = 3
输出:2, nums = [2,2,_,_]
解释:你的函数函数应该返回 k = 2, 并且 nums 中的前两个元素均为 2。
你在返回的 k 个元素之外留下了什么并不重要(因此它们并不计入评测)。

示例 2:

输入:nums = [0,1,2,2,3,0,4,2], val = 2
输出:5, nums = [0,1,4,0,3,_,_,_]
解释:你的函数应该返回 k = 5,并且 nums 中的前五个元素为 0,0,1,3,4。
注意这五个元素可以任意顺序返回。
你在返回的 k 个元素之外留下了什么并不重要(因此它们并不计入评测)。

提示:

  • 0 <= nums.length <= 100
  • 0 <= nums[i] <= 50
  • 0 <= val <= 100

暴力法

时间复杂度:O(n^2)  空间复杂度:O(1)

class Solution {
    public int removeElement(int[] nums, int val) {
        int l = nums.length;
        for(int i = 0;i<l;i++){//i小于更新后的数组长度
            if(nums[i]==val){
                for(int j = i+1;j<l;j++){//j小于更新后的数组长度
                    nums[j-1]=nums[j];
                }
                l--;//删除元素后更新数组长度
                i--;//删除元素后,剩下元素的下标提前,i减1
            }
        }
        return l;
    }
}

双指针法(快慢指针法)

通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。

时间复杂度:O(n)   空间复杂度:O(1)

class Solution {
    public int removeElement(int[] nums, int val) {
        int fast = 0;//快指针用来记录非value的元素
        int slow = 0;//慢指针用来更新数组
        for(fast = 0;fast<nums.length;fast++){
            if(nums[fast]!=val){//快指针指向非val的元素时,更新数组,元素下标为slow
                nums[slow]=nums[fast];
                slow++;
            }
        }
        return slow;
    }
}

26.删除有序数组中的重复项

给你一个 非严格递增排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。

考虑 nums 的唯一元素的数量为 k ,你需要做以下事情确保你的题解可以被通过:

  • 更改数组 nums ,使 nums 的前 k 个元素包含唯一元素,并按照它们最初在 nums 中出现的顺序排列。nums 的其余元素与 nums 的大小不重要。
  • 返回 k 。

判题标准:

系统会用下面的代码来测试你的题解:

int[] nums = [...]; // 输入数组
int[] expectedNums = [...]; // 长度正确的期望答案

int k = removeDuplicates(nums); // 调用

assert k == expectedNums.length;
for (int i = 0; i < k; i++) {
    assert nums[i] == expectedNums[i];
}

如果所有断言都通过,那么您的题解将被 通过

示例 1:

输入:nums = [1,1,2]
输出:2, nums = [1,2,_]
解释:函数应该返回新的长度 2 ,并且原数组 nums 的前两个元素被修改为 1, 2 不需要考虑数组中超出新长度后面的元素。

示例 2:

输入:nums = [0,0,1,1,1,2,2,3,3,4]
输出:5, nums = [0,1,2,3,4]
解释:函数应该返回新的长度 5 , 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4 。不需要考虑数组中超出新长度后面的元素。

提示:

  • 1 <= nums.length <= 3 * 104
  • -104 <= nums[i] <= 104
  • nums 已按 非严格递增 排列
class Solution {
    public int removeDuplicates(int[] nums) {
        int fast = 1;//nums[0]第一个元素不需要修改,从下标1开始
        int slow = 1;
        for(fast = 1;fast<nums.length;fast++){
            if(nums[fast-1]!=nums[fast]){
                nums[slow]=nums[fast];
                slow++;
            }
        }
        return slow;
    }
}

283.移动零

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

请注意 ,必须在不复制数组的情况下原地对数组进行操作。

示例 1:

输入: nums = [0,1,0,3,12]
输出: [1,3,12,0,0]

示例 2:

输入: nums = [0]
输出: [0]

提示:

  • 1 <= nums.length <= 104
  • -231 <= nums[i] <= 231 - 1
class Solution {
    public void moveZeroes(int[] nums) {
        int fast = 0;
        int slow = 0;
        for(fast = 0;fast<nums.length;fast++){
            if(nums[fast]!=0){
                nums[slow] = nums[fast];
                slow++;
            }
        }
        while(slow<nums.length){
            nums[slow]=0;
            slow++;
        }
    }
}

844.比较含退格的字符串

给定 s 和 t 两个字符串,当它们分别被输入到空白的文本编辑器后,如果两者相等,返回 true 。# 代表退格字符。

注意:如果对空文本输入退格字符,文本继续为空。

示例 1:

输入:s = "ab#c", t = "ad#c"
输出:true
解释:s 和 t 都会变成 "ac"。

示例 2:

输入:s = "ab##", t = "c#d#"
输出:true
解释:s 和 t 都会变成 ""。

示例 3:

输入:s = "a#c", t = "b"
输出:false
解释:s 会变成 "c",但 t 仍然是 "b"。

提示:

  • 1 <= s.length, t.length <= 200
  • s 和 t 只含有小写字母以及字符 '#'

进阶:

  • 你可以用 O(n) 的时间复杂度和 O(1) 的空间复杂度解决该问题吗?

1.求出两个退格后的字符串,再比较,空间复杂度较大

class Solution {
    public static String changeS(String s) {
		StringBuilder ss = new StringBuilder(s);
		int skipS=0;
		int slow = s.length()-1;
		for(int fast = ss.length()-1;fast>=0;fast--) {
			if(ss.charAt(fast)=='#') {
				skipS++;
			}else {
				if(skipS==0) {
					ss.setCharAt(slow, ss.charAt(fast));
					slow--;
				}else if(skipS != 0) {
					skipS--;
				}
			}
		}
		while(slow>=0) {
			ss.setCharAt(slow--, ' ');
		}
		return ss.toString().trim();
	}

	public static String changeT(String t) {
		StringBuilder tt = new StringBuilder(t);
		int skipT=0;
		int slow = t.length()-1;
		for(int fast = tt.length()-1;fast>=0;fast--) {
			if(tt.charAt(fast)=='#') {
				skipT++;
			}else {
				if(skipT==0) {
					tt.setCharAt(slow, tt.charAt(fast));
					slow--;
				}else if(skipT != 0) {
					skipT--;
				}
			}
		}
		while(slow>=0) {
			tt.setCharAt(slow--, ' ');
		}
		return tt.toString().trim();
		
	}
    public boolean backspaceCompare(String s, String t) {
        return changeS(s).equals(changeT(t));
    }
}

2.从右往左遍历,找到两个字符串未删除的字符,字符间作比较,空间复杂度低

class Solution {
    public boolean backspaceCompare(String s, String t) {
        int i = s.length()-1;//从字符串右边开始遍历
        int j = t.length()-1;
        int skipS = 0;
        int skipT = 0;
        while(i>=0||j>=0) {
        	while(i>=0) {//找到字符串s不需要删除的字符位置
        		if(s.charAt(i)=='#') {
        			skipS++;
        			i--;
        		}else{
        			if(skipS>0) {
        				skipS--;
        				i--;
        			}
        			else if(skipS==0) {
        				break;
        			}
        		}
        	}
        	
        	while(j>=0) {//找到字符串t不需要删除的字符位置
        		if(t.charAt(j)=='#') {
        			skipT++;
        			j--;
        		}else{
        			if(skipT>0) {
        				skipT--;
        				j--;
        			}
        			else if(skipT==0) {
        				break;
        			}
        		}
        	}
            
        	if(i>=0&&j>=0) {//如果字符串为空,或者左边都是‘#’,下标会变成-1,导致超出下标范围
        		if(s.charAt(i)!=t.charAt(j)) {//比较两个字符,不相等返回false
            		return false;
            	}
        	}
        	
        	i--;
        	j--;
        }
        
        if(i==j) {//如果两个字符串为空,或者前面都是‘#’,最后i,j也相等
        	return true;
        }else {//字符长度不同
        	return false;
        }
    }
}

977.有序数组的平方

给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。

    示例 1:

    输入:nums = [-4,-1,0,3,10]
    输出:[0,1,9,16,100]
    解释:平方后,数组变为 [16,1,0,9,100]
    排序后,数组变为 [0,1,9,16,100]

    示例 2:

    输入:nums = [-7,-3,2,3,11]
    输出:[4,9,9,49,121]
    

    提示:

    • 1 <= nums.length <= 104
    • -104 <= nums[i] <= 104
    • nums 已按 非递减顺序 排序

    进阶:

    • 请你设计时间复杂度为 O(n) 的算法解决本问题
    class Solution {
        public int[] sortedSquares(int[] nums) {
            int front = 0;
            int rear = nums.length-1;
            int[] ans = new int[nums.length];//新开一个数组记录答案
            int p = nums.length-1;//从尾部从大到小记录
            while(front<=rear){
                //也可以写成:-nums[front] > nums[rear]
                if(nums[front]*nums[front] > nums[rear]*nums[rear]){
                    ans[p]=nums[front]*nums[front];
                    front++;
                    p--;
                }else{
                    ans[p]=nums[rear]*nums[rear];
                    rear--;
                    p--;
                }
            }
            return ans;
        }
    }

    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

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

    抵扣说明:

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

    余额充值