1.双指针思想
2.删除元素专题
2.1原地移除所有数值等于val的元素
leetcode27,移除元素 给你一个数组 nums_ 和一个值 val,你需要 原地 移除所有数值等于 val _的元素,并返回移除后数组的新长度。 不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地修改输入数组。 元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
说明: 为什么返回数值是整数,但输出的答案是数组呢? 请注意,输入数组是以**「引用」**方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。 你可以想象内部操作如下: // nums 是以“引用”方式传递的。也就是说,不对实参作任何拷贝 int len = removeElement(nums, val); // 在函数里修改输入数组对于调用者是可见的。 // 根据你的函数返回的长度, 它会打印出数组中 该长度范围内 的所有元素。 for (int i = 0; i < len; i++) { print(nums[i]); }
示例 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。注意这五个元素可为任意顺序。你不需要考虑数组中超出新长度后面的元素。 :::info 思路: 很容易就想到双指针 :::
class Solution {
public int removeElement(int[] nums, int val) {
int index=0;
for (int i = 0; i < nums.length; i++) {
if(nums[i]!=val){
nums[index++]=nums[i];
}
}
return index;
}
}
2.2删除有序数组中的重复项
删除有序数组的重复项 给你一个 非严格递增排列 的数组 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 。不需要考虑数组中超出新长度后面的元素。
class Solution {
public int removeDuplicates(int[] nums) {
if(nums.length==1){
return 1;
}
int index=0;
for (int i = 1; i < nums.length; i++) {
if(nums[index]!=nums[i]){
nums[++index]=nums[i];
}
}
return index+1;
}
}
3.元素奇偶移动专题
class Solution {
public int[] sortArrayByParity(int[] nums) {
int j=0;
for (int i = 0; i < nums.length; i++) {
if(nums[i]%2==0){
int temp=nums[i];
nums[i]=nums[j];
nums[j++]=temp;
}
}
return nums;
}
}
4.数组轮转问题
数组轮转 :::info 思路1: 创建一个新数组,按照顺序存进去,再赋值给原数组 思路2:
- 首先对整个数组实行翻转,这样子原数组中需要翻转的子数组,就会跑到数组最前面。
- 这时候,从 k 处分隔数组,左右两数组,各自进行翻转即可。 :::
class Solution {
public void rotate(int[] nums, int k) {
//方法二
int x=k%nums.length;
reverseArr(nums,0,nums.length-1);
reverseArr(nums,0,x-1);
reverseArr(nums,x,nums.length-1);
//方法一
/* int x=k%nums.length;
int[] arr=new int[nums.length];
int index=0;
for (int i = nums.length-x; i < nums.length; i++) {
arr[index++]=nums[i];
}
for (int i = 0; i < nums.length-x; i++) {
arr[index++]=nums[i];
}
int j=0;
for (int i = 0; i < nums.length; i++) {
nums[i]=arr[j++];
}*/
}
private void reverseArr(int[] nums, int l, int r) {
while (l<r){
int temp=nums[l];
nums[l]=nums[r];
nums[r]=temp;
l++;
r--;
}
}
}
5.数组区间问题
汇总区间 :::info 思路: 定义两个指针:l,r 遍历数组: 拼接条件r+1==nums.length||nums[r]+1!=nums[r+1] :::
class Solution {
public static List<String> summaryRanges(int[] nums) {
List<String> list=new ArrayList<>();
int l=0;
for (int r=0; r < nums.length; r++) {
if(r+1==nums.length||nums[r]+1!=nums[r+1]){
if(r==l){
list.add(String.valueOf(nums[l]));
}else {
list.add(nums[l]+"->"+nums[r]);
}
l=r+1;
}
}
return list;
}
}
6.字符串替换空格问题
这是剑指offr中的题目,出现频率也很高:请实现一个函数,将一个字符串中的每个空格替换成
"%20”。例如,当字符串为We Are Happy..则经过替换之后的字符串为We%20Are%20 Happy..
首先要考虑用什么来存储字符串,如果是长度不可变的char数组,那么必须新申请一个更大的空间。如果
使用长度可变的空间来管理原始数组,或者原始数组申请得足够大,这时候就可能要求你不能申请0(n)大
小的空间,我们一个个看。
思路:首先扩充数组到每个空格替换成"%20"之后的大小。
然后从后向前替换空格,也就是双指针法,过程如下:
i指向新长度的末尾,j指向旧长度的末尾。
public class Solution {
public static void main(String[] args) {
String s="hello world ";
System.out.println(replaceSpace(s));
}
public static String replaceSpace(String s){
if(s==null||s.length()==1){
return s;
}
//扩充空间,空格数量的两倍
StringBuilder str=new StringBuilder();
for (int i = 0; i < s.length(); i++) {
if(s.charAt(i)==' '){
str.append(" ");
}
}
//没有空格,直接返回即可
if(str.length()==0){
return s;
}
//有空格,定义双指针
int l=s.length()-1;
s+=str.toString();
int r=s.length()-1;
char[] chars = s.toCharArray();
for(;l>=0;l--){
if(chars[l]==' '){
chars[r--]='0';
chars[r--]='2';
chars[r--]='%';
}else {
chars[r--]=chars[l];
}
}
return new String(chars);
}
}