27.移除元素
力扣题目链接
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
示例1:
输入:nums = [3,2,2,3], val = 3
输出:2, nums = [2,2]
解释:函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。你不需要考虑数组中超出新长度后面的元素。例如,函数返回的新长度为 2 ,而 nums = [2,2,3,3] 或 nums = [2,2,0,0],也会被视作正确答案。
示例2:
输入:nums = [0,1,2,2,3,0,4,2], val = 2
输出:5, nums = [0,1,4,0,3]
解释:函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。注意这五个元素可为任意顺序。你不需要考虑数组中超出新长度后面的元素。
提示:
- 0 <= nums.length <= 100
- 0 <= nums[i] <= 50
- 0 <= val <= 100
暴力法
使用2层for循环:第1层循环遍历数组元素,第2层循环更新数组。很明显:其时间复杂度O(n^2),空间复杂度O(1)
Java代码如下:
public class LeetCode27 {
public static int removeElement(int[] nums, int val) {
/*1.暴力法:两次for循环*//*
int size = nums.length;
for (int i = 0; i < size; i++) {
if (nums[i] == val) {
for (int j = i + 1; j < size; j++) {
nums[j - 1] = nums[j];
}
*//*因为下标i以后的元素(都还未曾处理)都向前移动了1位,所以i也要向前1位*//*
i--;
*//*此时数组的大小要-1*//*
size--;
}
}
return size;*/
/*2.1快慢指针法:通过1次for循环完成2个for循环的工作*//*
int slowIndex = 0;
for (int fastIndex = 0; fastIndex < nums.length; fastIndex++) {
if (nums[fastIndex] != val) {
nums[slowIndex++] = nums[fastIndex];
}
}
return slowIndex;*/
/*2.2双向指针法:改变元素相对顺序,确保了移动最少元素*/
int leftIndex = 0;
int rightIndex = nums.length - 1;
while (leftIndex <= rightIndex) {
/*找左边等于val的元素*/
while (leftIndex <= rightIndex && nums[leftIndex] != val) {
leftIndex++;
}
/*找右边不等于val的元素*/
while (leftIndex <= rightIndex && nums[rightIndex] == val) {
rightIndex--;
}
/*交换左边和右边的元素*/
if (leftIndex < rightIndex) {
nums[leftIndex++] = nums[rightIndex--];
}
}
return leftIndex;
}
}
JavaScript代码如下:
/**
* @param {number[]} nums
* @param {number} val
* @return {number}
*/
let removeElement = function(nums, val) {
//方法1和2.1均未改变元素顺序
/**1.暴力法:使用2个for循环,模拟数组删除过程 */
// let size = nums.length;
// for (let i = 0; i < size; i++) {
// if (nums[i] == val) {
// for (let j = i + 1; j < size; j++) {
// nums[j - 1] = nums[j];
// }
// i--;
// size--;
// }
// }
// return size;
/**2.1双指针之快慢指针: 使用1次for循环以达到2次for循环的功效 */
// let leftIndex = 0;
// for (let rightIndex = 0; rightIndex < nums.length; rightIndex++) {
// if (nums[rightIndex] != val) {
// nums[leftIndex++] = nums[rightIndex];
// }
// }
// return leftIndex;
/**2.2双指针之相向指针:改变了元素相对顺序,但确保了最少的移动次数 */
let leftIndex = 0,
rightIndex = nums.length - 1;
while (leftIndex <= rightIndex) {
// 左边找到等于val的值,这里对
while (leftIndex <= rightIndex && nums[leftIndex] != val) {
leftIndex++;
}
//右边找到不等于val的值
while (leftIndex <= rightIndex && nums[rightIndex] == val) {
rightIndex--;
}
if (leftIndex < rightIndex) {
nums[leftIndex++] = nums[rightIndex--];
}
}
return leftIndex
};
python代码如下:
class Solution:
def removeElement(self, nums: List[int], val: int) -> int:
slowIndex = 0
for fastIndex in range(len(nums)):
if nums[fastIndex] != val:
nums[slowIndex] = nums[fastIndex]
slowIndex += 1
return slowIndex
26.删除有序数组中的重复项
力扣题目链接
给你一个 升序排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。
考虑 nums 的唯一元素的数量为 k ,你需要做以下事情确保你的题解可以被通过:
- 更改数组 nums ,使 nums 的前 k 个元素包含唯一元素,并按照它们最初在 nums 中出现的顺序排列。nums 的其余元素与 nums 的大小不重要。
- 返回 k 。
示例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 * 1 0 4 10^4 104
- − 1 0 4 -10^4 −104 <= nums[i] <= 1 0 4 10^4 104
- nums已按升序排序
Java代码如下:
public class LeetCode26 {
public int removeDuplicates(int[] nums) {
int slowIndex = 1;
for (int fastIndex = 1; fastIndex < nums.length; fastIndex++) {
if (nums[fastIndex] != nums[slowIndex - 1]) {
/**
* 优化:当数组本身绝大多数是不重复元素时,减少不必要的复制
* 可以考虑最极端的情况:如,[1,2,3,4,5,6],即数组本身即为正确数组
* */
if (fastIndex - slowIndex + 1 > 1) {
nums[slowIndex] = nums[fastIndex];
}
slowIndex++;
}
}
return slowIndex;
}
}
JavaScript代码如下:
/**
* @param {number[]} nums
* @return {number}
*/
let removeDuplicates = function(nums) {
let slowIndex = 0;
for (let fastIndex = 1; fastIndex < nums.length; fastIndex++) {
if (nums[fastIndex] != nums[slowIndex]) {
if (fastIndex - slowIndex > 1) {
nums[slowIndex + 1] = nums[fastIndex];
}
slowIndex++;
}
}
return slowIndex + 1;
};
python代码如下:
class Solution:
def removeDuplicates(self, nums: List[int]) -> int:
slowIndex, fastIndex = 0, 1
while fastIndex < len(nums):
if nums[slowIndex] != nums[fastIndex]:
if fastIndex - slowIndex > 1:
nums[slowIndex + 1] = nums[fastIndex]
slowIndex += 1
fastIndex += 1
return slowIndex + 1
283.移动零
力扣题目链接
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
请注意 ,必须在不复制数组的情况下原地对数组进行操作。
示例1:
输入: nums = [0,1,0,3,12]
输出: [1,3,12,0,0]
示例2:
输入: nums = [0]
输出: [0]
提示:
- 1 <= nums.length <= 1 0 4 10^4 104
- − 2 31 -2^{31} −231 <= nums[i] <= 2 31 2^{31} 231 - 1
Java代码如下:
public class LeetCode283 {
public void moveZeroes(int[] nums) {
int left = 0, right = 0;
while (right < nums.length) {
if (nums[right] != 0) {
int t = nums[left];
nums[left] = nums[right];
nums[right] = t;
left++;
}
right++;
}
}
}
JavaScript代码如下:
/**
* @param {number[]} nums
* @return {void} Do not return anything, modify nums in-place instead.
*/
let moveZeroes = function(nums) {
let left = 0, right = 0;
while (right < nums.length) {
if (nums[right] != 0) {
let t = nums[left];
nums[left] = nums[right];
nums[right] = t;
left++;
}
right++;
}
};
Python代码如下:
class Solution:
def moveZeroes(self, nums: List[int]) -> None:
slowIndex = 0
for fastIndex in range(len(nums)):
if nums[fastIndex] != 0:
nums[slowIndex], nums[fastIndex] = nums[fastIndex], nums[slowIndex]
slowIndex += 1
fastIndex += 1
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 只含有小写字母以及字符‘#’
Java代码如下:
public class LeetCode844 {
public boolean backspaceCompare(String s, String t) {
char[] chs1 = s.toCharArray();
char[] chs2 = t.toCharArray();
return solveBackSpace(chs1).equals(solveBackSpace(chs2));
}
public String solveBackSpace(char[] chars) {
/**
* 采用快慢指针法:
* 慢指针指向已处理序列的尾部,即当前符合条件的序列长度
* 快指针指向未处理序列中符合判断条件的元素
*/
int slowIndex = 0;
for (int fastIndex = 0; fastIndex < chars.length; fastIndex++) {
if (chars[fastIndex] != '#') {
chars[slowIndex++] = chars[fastIndex];
} else if (slowIndex > 0) {
slowIndex--;
}
}
return new String(chars,0,slowIndex);
}
}
JavaScript代码如下:
/**
* @param {string} s
* @param {string} t
* @return {boolean}
*/
let backspaceCompare = function(s, t) {
return solveBackSpace(s) === solveBackSpace(t);
};
function solveBackSpace(string) {
let str = "";
for (const element of string) {
if (element !== '#') {
str += element;
} else if (str.length > 0) {
str = str.slice(0,str.length - 1);;
}
}
return str;
}
Python代码如下:
class Solution:
def backspaceCompare(self, s: str, t: str) -> bool:
return True if self.raw_string(s) == self.raw_string(t) else False
def raw_string(self, s: str) -> str:
fastIndex, s1 = 0, ""
while fastIndex < len(s):
if s[fastIndex] != '#':
s1 += s[fastIndex]
elif len(s1) > 0:
s1 = s1[:len(s1)-1]
fastIndex += 1
return s1
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 <= 1 0 4 10^4 104
- − 1 0 4 -10^4 −104 <= nums[i] <= 1 0 4 10^4 104
- nums已按非递减顺序排序
Java代码如下:
public class LeetCode977 {
public int[] sortedSquares(int[] nums) {
/**
* 1.暴力法:先平方在排序
* 时间复杂度为:O(n + nlogn)
* for (int i = 0; i < nums.length; i++) {
* nums[i] *= nums[i];
* }
* java.util.Arrays.sort(nums);
* return nums;
* */
/**
* 2.双指针法:相向指针,确定平方后的最大元素,直接放于新数组尾部
*/
int rightIndex = nums.length - 1;
int leftIndex = 0;
int[] result = new int[nums.length];
int newIndex = result.length - 1;
while (leftIndex <= rightIndex) {
if (nums[leftIndex] * nums[leftIndex] > nums[rightIndex] * nums[rightIndex]) {
result[newIndex--] = nums[leftIndex] * nums[leftIndex];
leftIndex++;
} else {
result[newIndex--] = nums[rightIndex] * nums[rightIndex];
rightIndex--;
}
}
return result;
}
}
JavaScript代码如下:
/**
* @param {number[]} nums
* @return {number[]}
*/
let sortedSquares = function(nums) {
/*1.暴力解法
for (let i = 0; i < nums.length; i++) {
nums[i] = Math.pow(nums[i], 2);
}
nums.sort((a, b) => a-b);
return nums;
*/
/*2.双向指针法:确定最大的平方数,并放入新数组中*/
let rightIndex = nums.length - 1;
let result = new Array(nums.length).fill(0);
let newIndex = result.length - 1;
for (let leftIndex = 0; leftIndex < rightIndex;) {
if (Math.pow(nums[leftIndex], 2) > Math.pow(nums[rightIndex], 2)) {
result[newIndex--] = Math.pow(nums[leftIndex], 2);
leftIndex++;
} else {
result[newIndex--] = Math.pow(nums[rightIndex], 2);
rightIndex--;
}
}
return result;
};
console.log(sortedSquares([-4,-1,0,3,10]));
Python代码如下:
class Solution:
def sortedSquares(self, nums: List[int]) -> List[int]:
count, leftIndex, rightIndex, ans = len(nums)-1 , 0, len(nums)-1, [0 for x in range(len(nums))]
while leftIndex <= rightIndex:
if nums[leftIndex] ** 2 >= nums[rightIndex] ** 2:
ans[count] = nums[leftIndex] ** 2
leftIndex += 1
else:
ans[count] = nums[rightIndex] ** 2
rightIndex -= 1
count -= 1
return ans
总结:
采用快慢指针法:
- 慢指针指向已经处理好序列的尾部,即其长度。
- 快指针指向未处理序列的符合条件的元素。
采用双向指针法:
- 改变了元素相对顺序(可根据题意看是否限制)。
- 确保了最少的移动次数。