删除元素,增加元素
不用双指针的数组:就是将数组的元素向前移或者向后移
双指针:解决大量元素的移动,直接将关键的元素移动,慢则是当前的元素,快则是检测前面的元素
常见的方式有:1.向前走 2.两头向中间 3.中间向两头
原地移除所有数值等于 val 的元素
思路:
向前走双指针
public static int removeElement(int[] nums, int val) { int slow = 0; //fast充当了快指针的角色 for (int fast = 0; fast < nums.length; fast++) { if (nums[fast] != val) { nums[slow] = nums[fast]; slow++; } } //最后剩余元素的数量 return slow; }
两头向中间
public int removeElement(int[] nums, int val) { int right = nums.length - 1; int left = 0; for (left = 0; left <= right; ) { if ((nums[left] == val) && (nums[right] != val)) { int tmp = nums[left]; nums[left] = nums[right]; nums[right] = tmp; } if (nums[left] != val) left++; if (nums[right] == val) right--; } return left ; }
优化:不管后面什么元素,直接覆盖,再来检查是否符合要求,这样减少一次判断,并且更加自动,类似与快排思想
public int removeElement(int[] nums, int val) { int right = nums.length-1; for (int left = 0; left <= right; ) { if (nums[left] == val) { nums[left] = nums[right ]; right--; } else { left++; } } return right+1; }
元素奇偶移动专题
思路:
将奇偶分开,使用两头向中间模式
public static i nt[] sortArrayByParity(int[] A) { int left = 0, right = A.length - 1; while (left < right) { //如果是偶数,则取模为0,否则肯定比0大的数 if (A[left] % 2 > A[right] % 2) { int tmp = A[left]; A[left] = A[right]; A[right] = tmp; } //偶数往前,保留奇数 if (A[left] % 2 == 0) left++; //奇数往前,保留偶数 if (A[right] % 2 == 1) right--; } return A; }
数组轮转问题
类似与旋转链表
public ListNode rotateRight(ListNode head, int k) { if(head == null || k == 0){ return head; } //这里三个变量都指向链表头结点 ListNode temp = head; ListNode fast = head; ListNode slow = head; int len = 0; //这里head先走一遍,统计出链表的元素个数,完成之后head就变成null了 while(head != null){ head = head.next; len++; } if(k % len == 0){ return temp; } // 从这里开始fast从头结点开始向后走 //这里使用取模,是为了防止k大于len的情况 //例如,如果len=5,那么k=2和7,效果是一样的 while((k % len) > 0){ k--; fast = fast.next; } // 快指针走了k步了,然后快慢指针一起向后执行 // 当fast到尾结点的时候,slow刚好在倒数第K个位置上 while(fast.next != null){ fast = fast.next; slow = slow.next; } ListNode res = slow.next; slow.next = null; fast.next = temp; return res; }
public void rotate(int[] nums, int k) { k %= nums.length; reverse(nums, 0, nums.length - 1); reverse(nums, 0, k - 1); reverse(nums, k, nums.length - 1); } public void reverse(int[] nums, int start, int end) { while (start < end) { int temp = nums[start]; nums[start] = nums[end]; nums[end] = temp; start += 1; end -= 1; } }
解决:
1.全部反转
2.找到指定区域再次反转