leetcode lecture on algorithm interview in Dachang 19. Array
Video Explanation (efficient learning): Click to learn
catalog:
6. Depth first & breadth first
10. Recursion & divide and conquer
Time complexity of Array Operations
-
Access: O(1)
-
Search: O(n)
-
Insert: average O(n), in the best case O(1), that is, insert O(1) at the end of the array, and in the worst case O(n)
-
Delete; Average O(n), in the best case O(1), that is, delete O(1) at the end of the array, and in the worst case O(n)
283. Move zero (easy)
The animation is too large. Click to view it
Method 1: traversal twice
- Idea: traverse the array and define the index j as the first position of the array. In case of non-0 elements, make the elements at position j equal to this non-0 element. After traversing the array, all the elements after position j are set to 0
- Complexity: time complexity O(n), space complexity O(1)
js:
var moveZeroes = function (nums) { let j = 0; for (let i = 0; i < nums.length; i++) { if (nums[i] !== 0) {//If a non-0 element is encountered, let num [j] = num [i], and then j++ nums[j] = nums[i]; j++; } } for (let i = j; i < nums.length; i++) {//The remaining elements are all 0 nums[i] = 0; } return nums; };
java:
class Solution { public void moveZeroes(int[] nums) { if(nums==null) { return; } int j = 0; for(int i=0;i<nums.length;++i) { if(nums[i]!=0) { nums[j++] = nums[i]; } } for(int i=j;i<nums.length;++i) { nums[i] = 0; } } }
Method 2: double pointer traversal at one time
- Idea: define the left and right pointers, move right from left to right, encounter non-0 elements, exchange the elements corresponding to left and right, and then exchange left++
- Complexity: time complexity O(n), space complexity O(1)
js:
var moveZeroes = function(nums) { let left=0,right=0 while(right<nums.length){ if(nums[right]!==0){//In case of non-0 elements, exchange the elements corresponding to left and right swap(nums,left,right) left++//left after swap++ } right++ } }; function swap(nums,l,r){ let temp=nums[r] nums[r]=nums[l] nums[l]=temp }
java:
class Solution { public void moveZeroes(int[] nums) { if(nums==null) { return; } int j = 0; for(int i=0;i<nums.length;i++) { if(nums[i]!=0) { int tmp = nums[i]; nums[i] = nums[j]; nums[j++] = tmp; } } } }
75. Color classification (medium)
The animation is too large. Click to view it
Method 1. Double pointer
- Idea: prepare two pointers p0 and p1. p0 points to 0 element and p1 points to 1. During initialization, both pointers point to the first position of the array. Then loop the array
- When you meet 1, exchange the current element and p1. Let p1 add 1 and move forward one bit
- The current element and p0 are exchanged when meeting 0. If p1 is less than p0, the element pointed to by p0 is 1 at this time. After exchanging with the element at position i, the past 1 position of the exchange is wrong, so the past 1 needs to be exchanged with p1. At this time, both p0 and p1 point to the correct element, so they need to move forward once. If p0 equals p1, the previous elements are all 0, so p0 and p1 also move forward once
- Complexity: time complexity O(n), n is the length of the array, and space complexity O(1)
js:
var sortColors = function (nums) { let p0 = 0 //Point to 0 let p1 = 0 //Point to 0 for (let i = 0; i < nums.length; i++) { if (nums[i] === 1) {//If the element pointed to by the current i is equal to 1, the current element and the element pointed to by p1 are exchanged let temp = nums[p1] nums[p1] = nums[i] nums[i] = temp p1++ } else if (nums[i] === 0) {//If the element pointed to by the current i is equal to 0, the current element and the element pointed to by p0 are exchanged let temp = nums[p0] nums[p0] = nums[i] nums[i] = temp //If p0 is less than p1, the element pointed to by p0 is 1 at this time. After exchanging with the element at position i, the past 1 position of this exchange is wrong, so the past 1 needs to be exchanged with p1 if (p0 < p1) { temp = nums[i]; nums[i] = nums[p1]; nums[p1] = temp; } //After each exchange of 0, move p0 and p1. If p0===p1, the previous code is 0. If p0 < p1, the previous code has been exchanged twice p0++ p1++ } } };
java
class Solution { public void sortColors(int[] nums) { int n = nums.length; int p0 = 0, p1 = 0; for (int i = 0; i < n; ++i) { if (nums[i] == 1) { int temp = nums[i]; nums[i] = nums[p1]; nums[p1] = temp; ++p1; } else if (nums[i] == 0) { int temp = nums[i]; nums[i] = nums[p0]; nums[p0] = temp; if (p0 < p1) { temp = nums[i]; nums[i] = nums[p1]; nums[p1] = temp; } ++p0; ++p1; } } } }
Method 2. Double pointer
- Idea: prepare two pointers. p0 points to element 0, all on its left are 0, p2 points to 2, and all on its right are 2. Then loop the array. When you loop to p2, it shows that the elements on the right of p2 are the correct number, so I < = p2
- If i points to element 2 and i is less than p2, the elements pointed to by p2 and i are constantly exchanged. Because the number exchanged may still be 2, this 2 i s in an incorrect position
- If i points to element 0 at this time, the elements pointed to by p0 and i are exchanged
- When the cycle is completed, both 0 and 2 are photographed, and the 1 in the middle is naturally in the correct position
- Complexity: time complexity O(n), n is the length of the array, and space complexity O(1)
js:
var sortColors = function (nums) { let p0 = 0;//Point to 0 let p2 = nums.length - 1;//Point 2 for (let i = 0; i <= p2; i++) {//When the loop reaches p2, it indicates that the elements on the right of p2 are correct numbers, so I < = p2 //If i points to element 2 and i is less than p2, the elements pointed to by p2 and i are constantly exchanged. Because the number exchanged may still be 2, this 2 i s in an incorrect position while (nums[i] === 2 && i < p2) { let temp = nums[i]; nums[i] = nums[p2]; nums[p2] = temp; p2--; } //If i points to element 0 at this time, the elements pointed to by p0 and i are exchanged if (nums[i] === 0) { let temp = nums[i]; nums[i] = nums[p0]; nums[p0] = temp; p0++; } } }; //Writing method 2 var sortColors = function (nums) { const swap = (list, p1, p2) => [list[p1], list[p2]] = [list[p2], list[p1]] let red = 0, blue = nums.length - 1, p = 0 while (p <= blue) { switch (nums[p]) { case 0: swap(nums, red++, p) p++ break; case 1://Meeting 1 always makes p + + in the right position even if 2 is exchanged p++ break; case 2: swap(nums, blue--, p) break; default: break; } } };
java
class Solution { public void sortColors(int[] nums) { int n = nums.length; int p0 = 0, p2 = n - 1; for (int i = 0; i <= p2; ++i) { while (i <= p2 && nums[i] == 2) { int temp = nums[i]; nums[i] = nums[p2]; nums[p2] = temp; --p2; } if (nums[i] == 0) { int temp = nums[i]; nums[i] = nums[p0]; nums[p0] = temp; ++p0; } } } } //Writing method 2 public class Solution { public void sortColors(int[] nums) { int len = nums.length; if (len < 2) { return; } int red = 0; int blue = len; int p = 0; while (p < blue) { if (nums[p] == 0) { swap(nums, p, red); red++; p++; } else if (nums[p] == 1) { p++; } else { blue--; swap(nums, p, blue); } } } private void swap(int[] nums, int index1, int index2) { int temp = nums[index1]; nums[index1] = nums[index2]; nums[index2] = temp; } }
167. Sum of two II - input ordered array (easy)
Method 1: dichotomy
- Idea: loop the array to find another element from the binary of the element on the right of the current element, so that their sum is target
- Complexity: the time complexity O(nlogn) traverses the array. Each traversal is divided into two parts. Space complexity O(1)
js:
var twoSum = function (numbers, target) { let len = numbers.length, left = 0, right = len - 1, mid = 0 for (let i = 0; i < len; ++i) {//Loop array, looking for another element from the right element dichotomy left = i + 1 while (left <= right) { mid = parseInt((right - left) / 2) + left if (numbers[mid] == target - numbers[i]) { return [i + 1, mid + 1] } else if (numbers[mid] > target - numbers[i]) { right = mid - 1 } else { left = mid + 1 } } } return [-1, -1] }
java:
class Solution { public int[] twoSum(int[] numbers, int target) { for (int i = 0; i < numbers.length; ++i) { int left = i + 1, right = numbers.length - 1; while (left <= right) { int mid = (right - left) / 2 + left; if (numbers[mid] == target - numbers[i]) { return new int[]{i + 1, mid + 1}; } else if (numbers[mid] > target - numbers[i]) { right = mid - 1; } else { left = mid + 1; } } } return new int[]{-1, -1}; } }
Method 2: double pointer
- Idea: start with the left and right pointers at both ends of the array, and then constantly judge the sum of the numbers pointed to by the two pointers and the size of the target. When the sum is large, the right moves one bit to the left, and when it is small, the left moves one bit to the right
- Complexity: the time complexity is O(n), and the array is traversed once in total. Space complexity O(1)
js:
var twoSum = function (numbers, target) { let [left, right] = [0, numbers.length - 1];//Left and right pointer while (left < right) {// if (numbers[left] + numbers[right] > target) {//And big right shift left one bit right--; } else if (numbers[left] + numbers[right] < target) {//And the left is shifted one bit to the right left++; } else { return [left + 1, right + 1]; } } };
java
class Solution { public int[] twoSum(int[] numbers, int target) { int left = 0, right = numbers.length - 1; while (left < right) { int sum = numbers[left] + numbers[right]; if (sum == target) { return new int[]{left + 1, right + 1}; } else if (sum < target) { ++left; } else { --right; } } return new int[]{-1, -1}; } }
209. Minimum length subarray (medium)
Method 1: sliding window
The animation is too large. Click to view it
- Idea: the left and right pointers are both sides of the sliding window. Use the sliding window to cycle the array and continuously expand the window. If the sum of elements in the window is greater than the target, start to shrink the window, and then update the minimum sliding window
- Complexity: time complexity O(n), elements in the array are traversed once, and space complexity O(1)
js:
var minSubArrayLen = function(target, nums) { const len = nums.length; let l = r = sum = 0, res = len + 1; //The largest window will not exceed its own length while(r < len) { sum += nums[r++];//enlarge a window while(sum >= target) { res = res < r - l ? res : r - l;//Update minimum sum-=nums[l++];//contract the window } } return res > len ? 0 : res; };
java:
class Solution { public int minSubArrayLen(int s, int[] nums) { int left = 0; int sum = 0; int res = Integer.MAX_VALUE; for (int right = 0; right < nums.length; right++) { sum += nums[right]; while (sum >= s) { res = Math.min(res, right - left + 1); sum -= nums[left++]; } } return res == Integer.MAX_VALUE ? 0 : res; } }
349. Intersection of two arrays (easy)
Method 1: Set
- Idea: first convert the array to set, then traverse the set with small length, and judge whether the elements in set1 exist in set2. If so, it is one of the intersections.
- Complexity: time complexity O(m+n), m, n is the length of two arrays, the time complexity of converting an array into a set is the length of the array, and the complexity of traversing to find the intersection is O(min(m,n)). The space complexity O(m+n) is the space of two sets
js:
var intersection = function (nums1, nums2) { let set1 = new Set(nums1); let set2 = new Set(nums2);//Convert array to set if (set1.size > set2.size) {//Traversal with a small size array [set1, set2] = [set2, set1] } const intersection = new Set(); for (const num of set1) {//Traverse set1 if (set2.has(num)) {//If the element does not exist in set2, an intersection is added intersection.add(num); } } return [...intersection];//Convert to array };
java:
class Solution { public int[] intersection(int[] nums1, int[] nums2) { Set<Integer> set1 = new HashSet<Integer>(); Set<Integer> set2 = new HashSet<Integer>(); for (int num : nums1) { set1.add(num); } for (int num : nums2) { set2.add(num); } return getIntersection(set1, set2); } public int[] getIntersection(Set<Integer> set1, Set<Integer> set2) { if (set1.size() > set2.size()) { return getIntersection(set2, set1); } Set<Integer> intersectionSet = new HashSet<Integer>(); for (int num : set1) { if (set2.contains(num)) { intersectionSet.add(num); } } int[] intersection = new int[intersectionSet.size()]; int index = 0; for (int num : intersectionSet) { intersection[index++] = num; } return intersection; } }
Method 2: sort + double pointer
The animation is too large. Click to view it
- Idea: sort the array, and then traverse the array with two pointers respectively. If the elements pointed to by the two pointers are equal, it is one of the intersection. Otherwise, compare the size of the elements pointed to by the two pointers and move forward with a smaller one
- Complexity: the time complexity is O(mlogm+nlogn). The time complexity of the two arrays is O(mlogm) and O(nlogn). Double pointer traversal requires O(m+n). The complexity depends on the larger O(mlogm+nlogn). Space complexity O(logm+logn) additional space used for sorting
js:
// nums1 = [4,5,9] // nums2 = [4,4,8,9,9] // intersection = [4,9] var intersection = function (nums1, nums2) { nums1.sort((x, y) => x - y);//sort nums2.sort((x, y) => x - y); const length1 = nums1.length, length2 = nums2.length; let index1 = 0,//Double pointer index2 = 0; const intersection = []; while (index1 < length1 && index2 < length2) {//Double pointer traversal array const num1 = nums1[index1], num2 = nums2[index2]; if (num1 === num2) {//If the elements pointed to by two pointers are equal, one of them intersects //Prevent duplicate join if (num1 !== intersection[intersection.length - 1]) { intersection.push(num1); } index1++; index2++; } else if (num1 < num2) { index1++;//Num1 < num2 indicates that mums1 needs to move to the right } else { index2++;//Num1 > num2 indicates that mums1 needs to move to the left } } return intersection; };
Java;
class Solution { public int[] intersection(int[] nums1, int[] nums2) { Arrays.sort(nums1); Arrays.sort(nums2); int length1 = nums1.length, length2 = nums2.length; int[] intersection = new int[length1 + length2]; int index = 0, index1 = 0, index2 = 0; while (index1 < length1 && index2 < length2) { int num1 = nums1[index1], num2 = nums2[index2]; if (num1 == num2) { if (index == 0 || num1 != intersection[index - 1]) { intersection[index++] = num1; } index1++; index2++; } else if (num1 < num2) { index1++; } else { index2++; } } return Arrays.copyOfRange(intersection, 0, index); } }
350. Intersection of two arrays II (easy)
Method 1: hash table
- Idea: count the frequency of each element in nums1, cycle nums2, and see whether the elements in nums2 exist in the mums1 frequency hash table. If so, add the result and reduce the frequency by 1
- Complexity: time complexity O(m+n), traversing two arrays, hash table operation complexity O(1). The spatial complexity O(min(m,n)) hashes arrays with small length.
js:
const intersect = (nums1, nums2) => { const map = {}; const res = []; if (nums1.length < nums2.length) { [nums1, nums2] = [nums2, nums1] } for (const num1 of nums1) {//Frequency of each element in nums1 if (map[num1]) { map[num1]++; } else { map[num1] = 1; } } for (const num2 of nums2) { //Traverse nums2 const val = map[num2]; if (val > 0) { //In nums1 res.push(num2); //Add res array map[num2]--; //If you match one, subtract one } } return res; };
java:
class Solution { public int[] intersect(int[] nums1, int[] nums2) { if (nums1.length > nums2.length) { return intersect(nums2, nums1); } Map<Integer, Integer> map = new HashMap<Integer, Integer>(); for (int num : nums1) { int count = map.getOrDefault(num, 0) + 1; map.put(num, count); } int[] intersection = new int[nums1.length]; int index = 0; for (int num : nums2) { int count = map.getOrDefault(num, 0); if (count > 0) { intersection[index++] = num; count--; if (count > 0) { map.put(num, count); } else { map.remove(num); } } } return Arrays.copyOfRange(intersection, 0, index); } }
Method 2: double pointer
- Idea: the double pointers p1 and p2 point to the elements in the two arrays. When p1 and p2 do not cross the boundary, start the cycle. If the element pointed to by p1 is large, move p2. If the element pointed to by p2 is large, move p1. If it is the same, add res and move the two pointers
- Complexity: the time complexity is O(mlogm+nlogn). m and N are the length of the array respectively. The sorting time complexity is O(mlogm+nlogn). The traversal of the two arrays is O(m+n). Spatial complexity O(logm+logn)
js:
const intersect = (nums1, nums2) => { nums1.sort((a, b) => a - b); nums2.sort((a, b) => a - b); //Sort two arrays const res = []; let p1 = 0;//Points to the element in nums1 let p2 = 0;//Points to the element in nums2 while (p1 < nums1.length && p2 < nums2.length) {//No crossing condition if (nums1[p1] > nums2[p2]) {//The element pointed to by p1 is large. Move p2 p2++; } else if (nums1[p1] < nums2[p2]) {//p2 points to a large element and moves p1 p1++; } else { //In case of the same, add res and move two pointers res.push(nums1[p1]); p1++; p2++; } } return res; };
java:
class Solution { public int[] intersect(int[] nums1, int[] nums2) { Arrays.sort(nums1); Arrays.sort(nums2); int length1 = nums1.length, length2 = nums2.length; int[] intersection = new int[Math.min(length1, length2)]; int p1 = 0, p2 = 0, index = 0; while (p1 < length1 && p2 < length2) { if (nums1[p1] < nums2[p2]) { p1++; } else if (nums1[p1] > nums2[p2]) { p2++; } else { intersection[index] = nums1[p1]; p1++; p2++; index++; } } return Arrays.copyOfRange(intersection, 0, index); } }
27. Remove element (easy)
- Idea: traverse the array with double pointers, initialize left at position 0, right at position num.length, and loop the array when left < right
- When num [left] = = = Val, use the position of right-1 to cover the element pointed to by the position of left, and then move right to the left
- When nums [left]== When Val, it indicates that the current element does not need to be overwritten, and leave it directly++
- Complexity: time complexity O(n), traversing the array. Space complexity O(1)
js:
//Method 1 //Example: [1,2,3,4,5], val=1 // [2,3,4,5,5], var removeElement = function(nums, val) { const n = nums.length; let left = 0;//The left pointer is initially at position 0 for (let right = 0; right < n; right++) {//Loop array with right pointer if (nums[right] !== val) {//If the current element is not val, the element at the left position is directly overwritten nums[left] = nums[right]; left++; } } return left; }; //The meaning of the optimization question is that the order of array elements can be ignored //When the array is [1,2,3,4,5] and the element to be deleted is 1, if you delete it directly, you need to move the elements after 1 forward one bit //When the array length is large, it consumes performance //Let's directly initialize right at the position of num.length and left at the position of 0 //Loop array when left < right //When num [left] = = = Val, use the position of right-1 to cover the element pointed to by the position of left, and then move right to the left //When nums [left]== When Val, it indicates that the current element does not need to be overwritten, and leave it directly++ //Example: [1,2,3,4,5], val=1 // [5,2,3,4,5] var removeElement = function(nums, val) { let left = 0, right = nums.length; while (left < right) { if (nums[left] === val) { nums[left] = nums[right - 1]; right--; } else { left++; } } return left; };
java:
class Solution { public int removeElement(int[] nums, int val) { int n = nums.length; int left = 0; for (int right = 0; right < n; right++) { if (nums[right] != val) { nums[left] = nums[right]; left++; } } return left; } } //optimization class Solution { public int removeElement(int[] nums, int val) { int left = 0; int right = nums.length; while (left < right) { if (nums[left] == val) { nums[left] = nums[right - 1]; right--; } else { left++; } } return left; } }
217. There are duplicate elements (easy)
Method 1. Sorting
- Idea: sort first, and then loop the array to judge whether the adjacent elements are the same
- Complexity: time complexity O(nlogn), space complexity O(logn), stack space required for sorting
js:
var containsDuplicate = function(nums) { nums.sort((a, b) => a - b);//sort const n = nums.length; for (let i = 0; i < n - 1; i++) { if (nums[i] === nums[i + 1]) {//Judge whether adjacent elements are the same return true; } } return false; };
java:
class Solution { public boolean containsDuplicate(int[] nums) { Arrays.sort(nums); int n = nums.length; for (int i = 0; i < n - 1; i++) { if (nums[i] == nums[i + 1]) { return true; } } return false; } }
Method 2. Hash table
- Idea: loop the array, store the elements in the set, and judge whether each element exists in the set
- Complexity: time complexity O(n), space complexity O(n)
js:
var containsDuplicate = function(nums) { const set = new Set(); for (const x of nums) { if (set.has(x)) { return true; } set.add(x); } return false; };
java:
class Solution { public boolean containsDuplicate(int[] nums) { Set<Integer> set = new HashSet<Integer>(); for (int x : nums) { if (!set.add(x)) { return true; } } return false; } }
238. Product of arrays other than itself (medium)
- Idea: traverse from left to right, record the product from left to the previous bit of the current position, then traverse from right to left, and multiply the product from left to the previous bit of the current position by the product of the right element.
- Complexity: time complexity O(n), space complexity O(1)
js:
var productExceptSelf = function (nums) { const res = []; res[0] = 1; //Traverse from left to right //Record the product from the left to the previous bit of the current position for (let i = 1; i < nums.length; i++) { res[i] = res[i - 1] * nums[i - 1]; } let right = 1; //Traverse from right to left //Multiply the product from the left to the previous bit of the current position by the product of the right element for (let j = nums.length - 1; j >= 0; j--) { res[j] *= right; right *= nums[j]; } return res; };
java
class Solution { public int[] productExceptSelf(int[] nums) { int[] res = new int[nums.length]; res[0] = 1; for (int i = 1; i < nums.length; i++) { res[i] = res[i - 1] * nums[i - 1]; } int right = 1; for (int i = nums.length - 1; i >= 0; i--) { res[i] *= right; right *= nums[i]; } return res; } }
905. Sort arrays by parity (easy)
Method 1. Sorting
- Idea: sort and compare, even number first and odd number last
- Complexity: time complexity O(nlogn), space complexity O(logn), sorting additional space
js:
var sortArrayByParity = function(A) { return A.sort((a, b) => (a & 1) - (b & 1)) };
Method 2. Double pointer
- Idea: the right pointer moves from right to left until it meets the first even number, and the left pointer moves from left to right until it meets the first odd number, and then switches positions
- Complexity: time complexity O(n), space complexity O(1)
js:
var sortArrayByParity = function(A, l = 0, r = A.length - 1) { while(l !== r) { while (r > 0 && A[r] & 1) r-- while (l < r && (A[l] & 1) === 0) l++ [A[l], A[r]] = [A[r], A[l]] } return A };
java:
class Solution { public int[] sortArrayByParity(int[] A) { int i = 0, j = A.length - 1; while (i < j) { if (A[i] % 2 > A[j] % 2) { int tmp = A[i]; A[i] = A[j]; A[j] = tmp; } if (A[i] % 2 == 0) i++; if (A[j] % 2 == 1) j--; } return A; } }
922. Sort array by parity II (easy)
Method 1. Double pointer
- Idea: if the even position of the loop encounters an odd number, then if the odd position of the loop encounters the first even number, it will intersect
- Complexity: time complexity O(n), space complexity O(1)
js:
const swap = (nums, i, j) => { const temp = nums[i]; nums[i] = nums[j]; nums[j] = temp; }; var sortArrayByParityII = function(nums) { const n = nums.length; let j = 1; for (let i = 0; i < n; i += 2) { if (nums[i] & 1) {//Loop even position if an odd number is encountered while (nums[j] & 1) {//Loop odd position if the first even number is encountered j += 2; } swap(nums, i, j);//Intersection substitution } } return nums; };
java:
class Solution { public int[] sortArrayByParityII(int[] nums) { int n = nums.length; int j = 1; for (int i = 0; i < n; i += 2) { if (nums[i] % 2 == 1) { while (nums[j] % 2 == 1) { j += 2; } swap(nums, i, j); } } return nums; } public void swap(int[] nums, int i, int j) { int temp = nums[i]; nums[i] = nums[j]; nums[j] = temp; } }