We know that for arrays, inserting and deleting elements at the end is more efficient, and the time complexity is O(1), but if you insert or delete elements in the middle or at the beginning, it will involve data movement, and the time complexity is O (N), the efficiency is low.
So the last article O(1) time to delete/find any element in the array talked about a technique, swapping the element to be deleted to the last one, and then deleting it, can avoid data movement.
PS: I have written more than 100 original articles carefully , and I have hand-in-hand brushed with 200 buckle questions, all of which are published in labuladong's algorithm cheat sheet , which is continuously updated . It is recommended to collect, brush the questions in the order of my articles , master various algorithm routines, and then cast them into the sea of questions.
Ordered array/linked list de-duplication
Let me first talk about how to de-duplicate an ordered array, first look at the following topic:
The function signature is as follows:
int removeDuplicates(int[] nums);
Obviously, since the array has been sorted, the duplicate elements must be connected together. It is not difficult to find them, but if every duplicate element is found, it will be deleted immediately, that is, the deletion operation is performed in the middle of the array. The overall time complexity will reach O(N^2).
PS: I have written more than 100 original articles carefully , and I have hand-in-hand brushed with 200 buckle questions, all of which are published in labuladong's algorithm cheat sheet , which is continuously updated . It is recommended to collect, brush the questions in the order of my articles , master various algorithm routines, and then cast them into the sea of questions.
Briefly explain what is in-situ modification:
If it is not modified in place, we directly new an int[]
array, put the elements after deduplication into this new array, and then return to this new array.
But in-situ deletion does not allow us to new the new array, we can only operate on the original array, and then return a length, so that we can get the elements after deduplication through the returned length and the original array.
This requirement is very common in array-related algorithmic problems. The general solution is the fast and slow pointer technique in the double pointer technique in the previous article .
We let the slow pointer slow
go behind, and the fast pointer fast
walks in front to explore the way, slow
and tell it if we find a non-repetitive element and let us move slow
forward. In this way, when the fast
pointer traverses the entire array nums
, the nums[0..slow]
elements are not repeated .
int removeDuplicates(int[] nums) { if (nums.length == 0) { return 0; } int slow = 0, fast = 0; while (fast < nums.length) { if (nums[fast] != nums[slow]) { slow++; // 维护 nums[0..slow] 无重复 nums[slow] = nums[fast]; } fast++; } // 数组长度为索引 + 1 return slow + 1; }
Look at the process of algorithm execution:
Simply expand, if you give you an ordered linked list, how to remove the duplication? This is the 83rd question. In fact, it is exactly the same as the array deduplication. The only difference is that the array assignment operation becomes an operation pointer:
ListNode deleteDuplicates(ListNode head) { if (head == null) return null; ListNode slow = head, fast = head; while (fast != null) { if (fast.val != slow.val) { // nums[slow] = nums[fast]; slow.next = fast; // slow++; slow = slow.next; } // fast++ fast = fast.next; } // 断开与后面重复元素的连接 slow.next = null; return head; }
The function signature is as follows:
int removeElement(int[] nums, int val);
The title requires us to delete nums
all val
the elements with values in situ, and we still need to use the speed pointer in the double pointer technique :
If you fast
encounter an element that needs to be removed, skip it directly, otherwise tell the slow
pointer and let it slow
go one step forward.
This is exactly the same as the solution to the array deduplication problem mentioned earlier, so I won’t draw GIF, just look at the code:
int removeElement(int[] nums, int val) { int fast = 0, slow = 0; while (fast < nums.length) { if (nums[fast] != val) { nums[slow] = nums[fast]; slow++; } fast++; } return slow; }
Note that there is an important difference between this and the deduplication of an ordered array . Here we nums[slow]
assign the value first and then give it slow++
, so that we can ensure nums[0..slow-1]
that it does not contain the value val
element, and the final result array length is slow
.
PS: I have written more than 100 original articles carefully , and I have hand-in-hand brushed with 200 buckle questions, all of which are published in labuladong's algorithm cheat sheet , which is continuously updated . It is recommended to collect, brush the questions in the order of my articles , master various algorithm routines, and then cast them into the sea of questions.
Move zero
This is Leikou question 283. Let me describe the following question:
Enter an array nums
for you, please modify it in place , move all the elements with value 0 in the array to the end of the array, the function signature is as follows:
void moveZeroes(int[] nums);
For example nums = [0,1,4,0,2]
, if you give you input , your algorithm does not return a value, but it will nums
modify the array in place [1,4,2,0,0]
.
Combining the several questions mentioned before, do you already have the answers?
The title lets us move all 0s to the end. In fact, it is equivalent to removing nums
all 0s, and then assign the following elements to 0.
So we can reuse the removeElement
function of the previous question :
void moveZeroes(int[] nums) { // Remove all 0 in nums // Return the length of the array after removing 0 int p = removeElement(nums, 0); // Assign all elements after p to 0 for (; p <nums.length; p++) { nums[p] = 0; } } // See the code above to achieve int removeElement(int[] nums, int val);
At this point, the four "modification in place" algorithm problems are finished. In fact, the core is still the speed pointer technique. Have you learned it?