1.删除数组内元素
1.1原地删除数组内数值等于val的元素
方法一:快慢双指针
思路:两指针的起点都是数组的首部,fast指针表示当前访问的元素,slow指针表示指针之前的元素都是有效元素,fast指针负责找到数值 != val 的元素 ,找到后slow,fast指针的元素互换,并且slow指针前进一步...
public int removeElement(int[] arr,int val){
//slow指针之前的代表有效元素
int slow = 0;
//fast指针负责遍历数组并找到 元素 != val 的元素
for (int fast = 0;fast< arr.length;fast++){
if (arr[fast] != val){
arr[slow] = arr[fast];
slow++;
}
}
return slow;
}
方法二:对撞双指针
思路:两指针一个left,一个right,right指针找到数值 != val 的元素 与left指针找到数值 == val 的元素互换,当left<=right,left以及左侧就是删除了数值val元素的有效数组
public int removeElement(int[] arr,int val){
int left = 0;
int right = arr.length-1;
for ( left = 0;left <= right;){
if (arr[left]==val && arr[right] != val){
int temp = arr[left];
arr[left] = arr[right];
arr[right] = temp;
}
if (arr[left] != val) left++;
if (arr[right] == val) right --;
}
return left;
}
1.2删除有序数组的重复项
双指针思想:fast负责遍历数组,slow负责指向有效数组最后一个元素
fast指针的元素 != slow指针的元素,slow指针的元素发生变化......
slow赋初值为1,从数组索引为1开始考虑是否有效......
public int removeRepeat(int[] arr){
int slow = 1;
for (int fast = 0; fast<arr.length; fast++){
if (arr[fast] != arr[slow-1]){
arr[slow] = arr[fast];
slow++;
}
}
return slow;
}
2.元素奇偶移动专题
题目:按奇偶排序数组,偶数元素后面是奇数元素
最简单的思路:开辟新数组空间,遍历要排序的数组两遍,分别挑选偶元素和奇元素在新数组排列,但是不推荐
推荐思路:采用双指针,核心是left寻找奇元素,right寻找偶元素,交换两指针元素
public int[] sortArrayByParity(int[] arr){
//left指针找奇元素,right指针找偶元素...SWAP
int left = 0;
int right = arr.length-1;
for (left = 0;left <= right;){
if (arr[left]%2 !=0 && arr[right]%2 == 0){
int temp = arr[left];
arr[left] = arr[right];
arr[right] = temp;
}
if (arr[left]%2 ==0) left++;
if (arr[right]%2 != 0) right--;
}
return arr;
}
3.数组轮换问题
题意:输入nums=[1,2,3,4,5,6,7],k=3
输出:[5,6,7,1,2,3,4]
思路:①先把原数组进行反转;②从k处分隔成两部分 [7,6,5],[4,3,2,1];③两部分分别进行反转
!!! %= 运算符的使用 :取余后把值重新赋值
/**
* 向右轮转数组k个位置,掉用了reverse()
* @param arr
* @param key
* @return
*/
public void rotate(int[] arr,int key){
key %= arr.length;
//数组总体反转
reverse(arr,0,arr.length-1);
//反转后的数组[0,K-1],[K,arr.length-1]区间反转
reverse(arr,0,key-1);
reverse(arr,key,arr.length-1);
}
/**
* 反转数组
* @param arr
* @return
*/
public void reverse(int[] arr,int start ,int end){
while (start < end){
//temp 暂存区
int temp = arr[start];
arr[start] = arr[end];
arr[end] = temp;
start ++;
end --;
}
}
4.数组的区间问题
题意:给定一个无重复的有序数组,返回恰好覆盖数组所有数字的最小有序区间范围列表
例如 nums=[0,1,2,4,5,7]
------->返回:["0->2","4->5","7"]
核心思想:使用双指针fast(遍历数组),slow(定位区间的开始),判断 fast +1 == arr.length
fast指针是否达到数组边界,arr[fast]+1 != arr[fast + 1] 判断是否是区间......
补充:ArrayList 类是一个可以动态修改的数组,与普通数组的区别就是它是没有固定大小的限制
public List<String> numsRange(int[] arr){
//存放返回的有效区间 字符串
List<String> res = new ArrayList<>();
//定义两个指针
int fast = 0;
int slow = 0;
for (fast =0;fast<arr.length;fast++){
//fast+1 到边界 或者 arr[fast+1] != arr[fast] + 1 ,即 [slow,fast]是一组有效区间
if (fast+1 == arr.length || arr[fast+1] != arr[fast]+1){
//将[slow,fast] 写入结果
StringBuffer sb = new StringBuffer();
sb.append(arr[slow]);
if (slow != fast){
sb.append("->").append(arr[fast]);
}
res.add(sb.toString());
// 将slow 更新为 下一个区间的起点
slow = fast+1;
}
}
return res;
}
5.字符串替换空格问题
题意:把字符串的空格替换成 %20
思路一:申请一个新空间,存放替换空格为 %20 的字符串,遍历字符串,若字符串的元素为空格,则替换为 %20
public String replaceSpace(String str){
//申请新空间
String res = "";
for (int i =0;i<str.length();i++){
//按索引顺序取出字符串的元素
char c = str.charAt(i);
if (c==' '){
res += "%20" ;
}else {
res += c ;
}
}
return res;
}
思路二:先遍历字符串,得到字符串内的空格个数,定义新的字符串长度,该长度可以容纳替换空格为%20后的新串,定义两个指针,一个在旧字符串的尾部,一个在新字符串的尾部,旧字符串从后往前遍历,如果旧字符串的fast指针处元素不是空格,则新字符串slow处添加该元素,否则新字符串从slow处后往前插入 ‘0’,‘2’,‘%’,直到fast指针遍历到头部 并且 两指针相遇 ,替换完成......
public String replaceSpace(StringBuffer str){
if (str == null)
return null;
//获取旧字符串的长度
int len = str.length();
//定义空格的个数
int numsOfBlank = 0;
//遍历获取旧字符串的空格个数
for (int i = 0; i < len; i++) {
if (str.charAt(i)== ' ')
numsOfBlank ++;
}
//定义新字符串的长度
str.setLength((len+2*numsOfBlank));
//定义两指针
int fast = len -1;
int slow = len+2*numsOfBlank -1;
while (fast>=0 && slow>fast){
char c = str.charAt(fast);
if (c== ' '){
fast --;
str.setCharAt(slow--,'0');
str.setCharAt(slow--,'2');
str.setCharAt(slow--,'%');
}else {
str.setCharAt(slow,c);
slow--;
fast--;
}
}
return str.toString();
}