数组理论基础:移除元素(6月7日-6月8日)

54 阅读4分钟

2:移除元素

库函数的erase时间复杂度为O(n)

题目

1:移除元素

leetcode.cn/problems/re…

方法1:暴力法

public int removeElement(int[] nums, int val) {
        //1:暴力法
        int len = nums.length;
            for(int i = 0; i < len;i++){
                if(nums[i] == val){
                    for(int j = i+1; j < len; j++){
                        nums[j-1] = nums[j];
                    }
                    i--; // 注意:因为下标i以后的数值都向前移动了一位,所以i也向前移动一位,
                    len--;
                }
            }
            return len;
    }

这里需要注意的是:因为下标i以后的数值都向前移动了一位,所以i也向前移动一位。

方法2:

快慢指针法: 快指针用于查找新数组中的元素,慢指针用于指向新数组的下标

//for循环写法
class Solution {
    public int removeElement(int[] nums, int val) {
        //2:双指针法
        int slow = 0;
        for(int fast = 0;fast < nums.length; fast++){
            if(nums[fast] != val){
                nums[slow] = nums[fast];
                slow++;
            }
        }
        return slow;
    }
}
//while循环写法
class Solution {
    public int removeElement(int[] nums, int val) {
        //2:双指针法
        int slow = 0;
        int fast = 0;
        while(fast < nums.length){
            if(nums[fast] != val){
                nums[slow] = nums[fast];
                slow++;
                fast++;
            }
            else{
                fast++;
            }
        }
        return slow;
    }
}

//这里slow不会+1是因为当slow+1的时候,slow指向的元素不一定是有效的

2:删除有序数组中的重复项

leetcode.cn/problems/re…

class Solution {
    public int removeDuplicates(int[] nums) {
        int slow = 0;
        for(int fast = 1;fast < nums.length;fast++){
            if(nums[fast] != nums[slow])
            {
                nums[slow+1] = nums[fast];
                slow++;
            }
        }
        return slow+1;  //这里slow+1是因为新数组中至少会有一个元素,当slow+1的时候,slow指向的元素是有效的
    }
}

//这里slow+1是因为新数组中至少会有一个元素,当slow+1的时候,slow指向的元素是有效的

3:移动零

leetcode.cn/problems/mo…

class Solution {
    public void moveZeroes(int[] nums) {
        //双指针法将元素前移
        int slow = 0;
        for(int fast = 0;fast < nums.length;fast++){
            if(nums[fast] != 0){
                nums[slow] = nums[fast];
                slow++;
            }
        }
        //将后面的元素置0
        for(; slow < nums.length;slow++){
            nums[slow] = 0;
        }
    }
}

这道题后续还需要看看,暴力解法还有点问题

6月7日打卡完毕

4:比较含退格的字符串

leetcode.cn/problems/ba…

思路:定义两个指针分别指向两个数组的尾部,并且定义backspaceS和backspaceT从后往前找,会遇到三种情况
情况1:当前指针S指向了#,则backspaceS++,S--。
情况2:当前指针S指向了字母,若则backspaceS>0,则backspaceS--,S--。
前两种情况是不能比较的,需要等两个数组全部获取到当前有效的字母,才能进行判断。
情况3:当前指针S指向了字母,若则backspaceS<=0,并且T指针指向的也是一个有效的字母,则开始判断,不相等就返回false,相等则继续判断(S--,T--)

class Solution {
    public boolean backspaceCompare(String s, String t) {
        int i = s.length() - 1;
            int j = t.length() - 1;
            int backspaceS = 0;
            int backspaceT = 0;
            while(i>=0 || j>=0){
                while(i>=0){//处理字符串S
                    if(s.charAt(i) == '#'){ //如果当前字符为退格,则backspaceS+1,指针向前移动
                        backspaceS++;
                        i--;
                    }
                    else if(s.charAt(i) != '#' && backspaceS>0){//如果当前字符为字母且backspaceS>0,指针向前移动
                        backspaceS--;
                        i--;
                    }
                    else{//如果当前字符为字母且backspaceS<=0,则当前指针指向元素有效,退出循环,等待T数组
                        break;
                    }
                }
                while(j>=0){//处理字符串T
                    if(t.charAt(j) == '#'){ //如果当前字符为退格,则backspaceT+1,指针向前移动
                        backspaceT++;
                        j--;
                    }
                    else if(t.charAt(j) != '#' && backspaceT>0){//如果当前字符为字母且backspaceT>0,指针向前移动
                        backspaceT--;
                        j--;
                    }
                    else{//如果当前字符为字母且backspaceT<=0,则当前指针指向元素有效,退出循环,等待T数组
                        break;
                    }
                }
                //若不相等则返回
                
                //这里有问题:不会进入第二个循环,但是会报第二个循环进行时候的越界错误,暂时不清楚原因
                if(i>=0 && j>=0 && s.charAt(i) != t.charAt(j)){
                    return false;
                }
                

                //若两个string中有一个的指针已经走到头了,则返回fasle
                if((i<0 && j >=0) || (i>=0 && j<0)){
                    return false;
                }
                i--;
                j--;
            }
            return true;
    }
}

总结:记一下这里的格式,即分别判断两个数组,while中嵌套两个while,但是时间复杂度仍是O(n).
这里还有一个问题:不会进入第二个循环,但是会报第二个循环进行时候的越界错误,暂时不清楚原因,需要加上i>=0 && j>=0才能解决问题。后续需要解决这个问题

5:有序数组的平方

见下一节