Leetcode 141 & 142. Linked List Cycle I & II

Given a linked list, determine if it has a cycle in it.

Follow up:
Can you solve it without using extra space?

Analysis:

Typical two pointer questions. Give two pointers fast and slow, fast run 2 steps and slow run 1 step. If there’s a cycle, finally slow == fast. If no cycle, fast == null || fast.next == null.

Time complexity: O(n)

Space complexity: O(1)

Code is below:

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public boolean hasCycle(ListNode head) {
        // O(n)
        
        if (head == null || head.next == null) {
            return false;
        }
        
        ListNode slow = head;
        ListNode fast = head.next;
        
        // while (slow != fast) {
        //     if (fast == null || fast.next == null) {
        //         return false;
        //     }
            
        //     slow = slow.next;
        //     fast = fast.next.next;
        // }
        
        // return true;
        
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
            
            if (slow == fast) {
                return true;
            }
        }
        
        return false;
    }
}

Followup:
Given a linked list, return the node where the cycle begins. If there is no cycle, return null.

Note: Do not modify the linked list.

Follow up:
Can you solve it without using extra space?

Analysis:
Follow the figure below:

list-cycle

链表头是X,环的第一个节点是Y,slow和fast第一次的交点是Z。各段的长度分别是a,b,c,如图所示。环的长度是L。slow和fast的速度分别是qs,qf。

第一次相遇时slow走过的距离:a+b,fast走过的距离:a+b+c+b。
因为fast的速度是slow的两倍,所以fast走的距离是slow的两倍,有 2(a+b) = a+b+c+b,可以得到a=c(这个结论很重要!)。
我们发现L=b+c=a+b,也就是说,从一开始到二者第一次相遇,循环的次数就等于环的长度。
我们已经得到了结论a=c,那么让两个指针分别从X和Z开始走,每次走一步,那么正好会在Y相遇!也就是环的第一个节点。
Time complexity: O(n)
Space complexity: O(1)
Code is below:
/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode detectCycle(ListNode head) {
        // O(n)
        
        if (head == null || head.next == null) {
            return null;
        }
        
        ListNode fast = head;
        ListNode slow = head;
        
        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
            
            if (fast == slow) {
                break;
            }
        }
        
        if (fast != slow) {
            return null;
        }
        
        fast = head;
        
        while (fast != slow) {
            fast = fast.next;
            slow = slow.next;
        }
        
        return fast;
    }
}

Leetcode 75. Sort Colors

Given an array with n objects colored red, white or blue, sort them so that objects of the same color are adjacent, with the colors in the order red, white and blue.

Here, we will use the integers 0, 1, and 2 to represent the color red, white, and blue respectively.

Note:
You are not suppose to use the library’s sort function for this problem.

click to show follow up.

Follow up:
A rather straight forward solution is a two-pass algorithm using counting sort.
First, iterate the array counting number of 0’s, 1’s, and 2’s, then overwrite array with total number of 0’s, then 1’s and followed by 2’s.

Could you come up with an one-pass algorithm using only constant space?

Analysis:

The basic (two-pass) way is to count the occurrence of 0, 1 and 2. Then overwrite the corresponding value.

A better (one-pass) way is to use three pointers. One is for left, one is right and one is the index.

If we encounter 0, we swap it with the left value, left++, index++; if we encounter 1, index++; if we encounter 2, swap it with the right value, right–;

Time complexity: O(n)

Space complexity: O(1)

An example for this algorithm is :

1 0 2 2 1 0
    ^         ^
    L         H
    M

    Mid != 0 || 2
    Mid++

    1 0 2 2 1 0
    ^ ^       ^
    L M       H

    Mid == 0
    Swap Low and Mid
    Mid++
    Low++

    0 1 2 2 1 0
      ^ ^     ^
      L M     H

    Mid == 2
    Swap High and Mid
    High--

    0 1 0 2 1 2
      ^ ^   ^
      L M   H

    Mid == 0
    Swap Low and Mid
    Mid++
    Low++

    0 0 1 2 1 2
        ^ ^ ^
        L M H

    Mid == 2
    Swap High and Mid
    High--

    0 0 1 1 2 2
        ^ ^
        L M
          H

    Mid <= High is our exit case

Code is below:

public class Solution {
    public void sortColors(int[] nums) {
        // O(n)
        
        if (nums == null || nums.length == 0) {
            return;
        }
        
        int left = 0; 
        int right = nums.length - 1;
        int i = 0;
        
        while (i <= right) {
            if (nums[i] == 0) {
                swap(nums, i, left);
                left++;
                i++;
            } else if (nums[i] == 2) {
                swap(nums, i, right);
                right--;
            } else {
                i++;
            }
        }
    }
    
    public void swap(int[] nums, int i, int j) {
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }
}

Leetcode 28. Implement strStr()

Implement strStr().

Returns the index of the first occurrence of needle in haystack, or -1 if needle is not part of haystack.

Analysis:

Brute force way. Go from the haystack and compare with needle, if it’s not the same, then break. Finally when j equals to the length of needle, we find the index.

Time complexity: O(mn)

Space complexity: O(1)

The code is below:

public class Solution {
    public int strStr(String haystack, String needle) {
        // O(mn)
        
        if (haystack == null || needle == null) {
            return -1;
        }
        
        int m = haystack.length();
        int n = needle.length();
        
        for (int i = 0; i < m - n + 1; i++) {
            int j = 0;
            for (j = 0; j < n; j++) {
                if (haystack.charAt(i + j) != needle.charAt(j)) {
                    break;
                }
            }
            
            if (j == n) {
                return i;
            }
        }
        
        return -1;
    }
}

Leetcode 88. Merge Sorted Array

Given two sorted integer arrays nums1 and nums2, merge nums2 into nums1 as one sorted array.

Note:
You may assume that nums1 has enough space (size that is greater or equal to m + n) to hold additional elements from nums2. The number of elements initialized in nums1 and nums2 are m and n respectively.

Analysis:

It’s hard to compare the two arrays from the beginning. So we compare them from the end. Then add the larger one to the end.

Note, after the whole process, we need to check whether there’s some leftover that we need to handle.

Time complexity: O(n)

Space complexity: O(1)

The code is below:

public class Solution {
    public void merge(int[] nums1, int m, int[] nums2, int n) {
        // O(m + n) O(1)
        
        // Go from the back, add number 1 by 1
        int i = m - 1;
        int j = n - 1;
        int index = m + n - 1;
        
        while (i >= 0 && j >= 0) {
            if (nums1[i] >= nums2[j]) {
                nums1[index--] = nums1[i--];
            } else {
                nums1[index--] = nums2[j--];
            }
        }
        
        // Left over
        while (i >= 0) {
            nums1[index--] = nums1[i--];
        }
        
        while (j >= 0) {
            nums1[index--] = nums2[j--];
        }
    }
}

Leetcode 283. Move Zeroes

Given an array nums, write a function to move all 0‘s to the end of it while maintaining the relative order of the non-zero elements.

For example, given nums = [0, 1, 0, 3, 12], after calling your function, nums should be [1, 3, 12, 0, 0].

Note:

  1. You must do this in-place without making a copy of the array.

  2. Minimize the total number of operations.

Analysis:

To move all 0s to the end, we need to go through the whole array. If the value is not zero, then put it in the array. Afterwards, put all values to be 0.

Time complexity: O(n)

Space complexity: O(1)

Code is below:

public class Solution {
    public void moveZeroes(int[] nums) {
        // O(n) O(1)
        
        if (nums == null || nums.length == 0) {
            return;
        }
        
        //Go through the array and put all non-zero element
        int index = 0;
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] != 0) {
                nums[index++] = nums[i];
            }
        }
        
        //Put all arrays left equal to zero
        for (int i = index; i < nums.length; i++) {
            nums[i] = 0;
        }
    }
}

Leetcode 26 & 27. Remove Duplicates from Sorted Array & Remove Element

Given an array and a value, remove all instances of that value in place and return the new length.

Do not allocate extra space for another array, you must do this in place with constant memory.

The order of elements can be changed. It doesn’t matter what you leave beyond the new length.

Example:
Given input array nums = [3,2,2,3], val = 3

Your function should return length = 2, with the first two elements of nums being 2.

Hint:

  1. Try two pointers.

  2. Did you use the property of “the order of elements can be changed”?

  3. What happens when the elements to remove are rare?

Analysis:

To remove the duplicates, we need to go through the whole array. If we find a value not equals to the val, then put it in the array and increase the index.

Time complexity: O(n)

Space complexity: O(1)

Below is the code:

public class Solution {
    public int removeElement(int[] nums, int val) {
        // O(n) O(1)
        
        // Corner case
        if (nums == null || nums.length == 0) {
            return 0;
        }
        
        int count = 0;
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] != val) {
                nums[count++] = nums[i];
            }
        }
        
        return count;
    }
}

Followup:
Given a sorted array, remove the duplicates in place such that each element appear only once and return the new length.

Do not allocate extra space for another array, you must do this in place with constant memory.

For example,
Given input array nums = [1,1,2],

Your function should return length = 2, with the first two elements of nums being 1 and 2 respectively. It doesn’t matter what you leave beyond the new length.

Analysis:
This problem is quite similar to the above, but here we will keep one copy of the duplicate. Because the array is sorted, if there’re duplicates, then it could only be like 0 1 1 2 3 3 3. So we still go over the array and check if nums[i] != nums[i-1] and if yes, then add it.

Note: we can go from the second value.

Time complexity: O(n)
Space complexity: O(1)

The code is below:

public class Solution {
    public int removeDuplicates(int[] nums) {
        // O(n) O(1)
        
        if (nums == null || nums.length == 0) {
            return 0;
        }
        
        int count = 1;
        for (int i = 1; i < nums.length; i++) {
            if (nums[i] != nums[i - 1]) {
                nums[count++] = nums[i];
            }
        }
        
        return count;
    }
}

Leetcode 18. 4Sum

Given an array S of n integers, are there elements a, b, c, and d in S such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target.

Note: The solution set must not contain duplicate quadruplets.

For example, given array S = [1, 0, -1, 0, -2, 2], and target = 0.

A solution set is:
[
  [-1,  0, 0, 1],
  [-2, -1, 1, 2],
  [-2,  0, 0, 2]
]

Analysis:
Very similar to the 3Sum, we only need to add one more loop.

Time complexity: O(n^3)
Space complexity: O(n)

The code is below:

public class Solution {
    public List<List> fourSum(int[] nums, int target) {
        //Two pointers O(n^3) O(n)
        
        List<List> result = new ArrayList<>();
        if (nums == null || nums.length < 4) {
            return result;
        }
        
        Arrays.sort(nums);
        for (int i = 0; i < nums.length - 3; i++) {
            // To skip duplicates
            if (i != 0 && nums[i] == nums[i - 1]) {
                continue;
            }
            
            for (int j = i + 1; j < nums.length - 2; j++) {
                // To skip duplicates
                if (j != i + 1 && nums[j] == nums[j - 1]) {
                    continue;
                }
                
                int left = j + 1;
                int right = nums.length - 1;
                
                while (left < right) {
                    int sum = nums[i] + nums[j] + nums[left] + nums[right];
                    if (sum == target) {
                        List temp = new ArrayList<>();
                        temp.add(nums[i]);
                        temp.add(nums[j]);
                        temp.add(nums[left]);
                        temp.add(nums[right]);
                        result.add(temp);
                        left++;
                        right--;
                        
                        // To skip duplicates
                        while (left < right && nums[left] == nums[left - 1]) {
                            left++;
                        }
                        
                        while (left < right && nums[right] == nums[right + 1]) {
                            right--;
                        }
                    } else if (sum < target) {
                        left++;
                    } else {
                        right--;
                    }
                }
            }
        }
        
        return result;
    }
}

Leetcode 15, 16 & 259. 3Sum 3Sum Closest & 3Sum Smaller

Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.

Note: The solution set must not contain duplicate triplets.

For example, given array S = [-1, 0, 1, 2, -1, -4],

A solution set is:
[
  [-1, 0, 1],
  [-1, -1, 2]
]

Analysis:

It’s very similar to the two sum with sorted array. Basically we need to sort the array, then use two pointers method to get the result.

Note: if we encounter duplicates, then we need to skip them and continue.

Time complexity: O(n^2)

Space complexity: O(n)

Below is the code:

public class Solution {
    public List<List> threeSum(int[] nums) {
        // Two pointers O(n^2) O(n)
        // Sort the array firstly, then use two pointers
        
        List<List> result = new ArrayList<>();
        if (nums == null || nums.length < 3) {
            return result;
        }
        
        Arrays.sort(nums);
        
        for (int i = 0; i < nums.length - 2; i++) {
            // To skip duplicates, like [0, 0, 0, 0]
            if (i != 0 && nums[i] == nums[i - 1]) {
                continue;
            }
            
            // Two sum two pointers below
            int left = i + 1;
            int right = nums.length - 1;
            
            while (left < right) {
                int sum = nums[i] + nums[left] + nums[right];
                
                if (sum == 0) {
                    List temp = new ArrayList<>();
                    temp.add(nums[i]);
                    temp.add(nums[left]);
                    temp.add(nums[right]);
                    result.add(temp);
                    left++;
                    right--;
                    
                    //To skip the duplicates
                    while (left < right && nums[left] == nums[left - 1]) {
                        left++;
                    }
                    
                    while (left < right && nums[right] == nums[right + 1]) {
                        right--;
                    }
                } else if (sum < 0) {
                    left++;
                } else {
                    right--;
                }
            }
        }
        
        return result;
    }
}

Followup:

Given an array S of n integers, find three integers in S such that the sum is closest to a given number, target. Return the sum of the three integers. You may assume that each input would have exactly one solution.

    For example, given array S = {-1 2 1 -4}, and target = 1.

    The sum that is closest to the target is 2. (-1 + 2 + 1 = 2).

Analysis:

The only difference here is to have a value of closest, we can initialize it to be the first three values then update it.

Time complexity: O(n^2)

Space complexity: O(1)

The code is below:

public class Solution {
    public int threeSumClosest(int[] nums, int target) {
        // Two pointers O(n^2) O(1)
        
        if (nums == null || nums.length < 3) {
            return 0;
        }
        
        Arrays.sort(nums);
        int closest = nums[0] + nums[1] + nums[2];
        
        for (int i = 0; i < nums.length - 2; i++) {
            // To skip duplicates, like 0, 0, 0, 0
            if (i != 0 && nums[i] == nums[i - 1]) {
                continue;
            }
            
            int left = i + 1;
            int right = nums.length - 1;
            
            while (left < right) {
                int sum = nums[i] + nums[left] + nums[right];
                if (Math.abs(sum - target) < Math.abs(closest - target)) {
                    closest = sum;
                } else if (sum < target) {
                    left++;
                } else {
                    right--;
                }
            }
        }
        
        return closest;
    }
}

Followup:

Given an array of n integers nums and a target, find the number of index triplets i, j, k with 0 <= i < j < k < n that satisfy the condition nums[i] + nums[j] + nums[k] < target.

For example, given nums = [-2, 0, 1, 3], and target = 2.

Return 2. Because there are two triplets which sums are less than 2:

[-2, 0, 1]
[-2, 0, 3]

Follow up:
Could you solve it in O(n2) runtime?

Analysis:

very similar to 3Sum, only difference is to update the count that satisfies the condition. Note that the count will be updated to be right – left.

Time complexity: O(n^2)

Space complexity: O(1)

The code is below:

public class Solution {
    public int threeSumSmaller(int[] nums, int target) {
        // Two pointers O(n^2) O(1)
        
        if (nums == null || nums.length < 3) {
            return 0;
        }
        
        Arrays.sort(nums);
        
        int count = 0;
        
        for (int i = 0; i < nums.length - 2; i++) {
            // Below is two sum
            int left = i + 1;
            int right = nums.length - 1;
            
            while (left < right) {
                if (nums[i] + nums[left] + nums[right] < target) {
                    // There're right - left pairs satisfied the condition
                    count += right - left;
                    left++;
                } else {
                    right--;
                }
            }
        }
        
        return count;
    }
}

Leetcode 349 Intersection of Two Arrays 1 & 2

Leetcode 349 Intersection of Two Arrays 1

Given two arrays, write a function to compute their intersection.

Example:
Given nums1 = [1, 2, 2, 1], nums2 = [2, 2], return [2].

Note:

  • Each element in the result must be unique.
  • The result can be in any order.
Analysis:
This problem can be solved by different methods: Hashset and Two pointers
HashSet: no duplicate and no order
  • Put numbers in nums1 in a hashset, have another set for result
  • Go through nums2 and to see if set contains the number, if contains && resultset not contains, put it in the resultset
  • Transfer the numbers out to be the result int[]

Time complexity: O(n)

Space complexity: O(n)

Two pointers:

  • Sort both array
  • Two pointers start and if nums1[i] < nums2[j], i++; if nums[i] > nums2[j], j++; else add to a set and i++, j++
  • Transfer the numbers out to be the result int[]

Time complexity: O(nlogn)

Space complexity: O(n)

public class Solution {
    public int[] intersection(int[] nums1, int[] nums2) {
        // corner case
        if (nums1 == null || nums2 == null) {
            return null;
        }
        
        
        // Method 1 hashset O(n)
        HashSet set = new HashSet<>();
        HashSet resSet = new HashSet<>();
        
        for (int i = 0; i < nums1.length; i++) {
            set.add(nums1[i]);
        }
        
        
        for (int i = 0; i < nums2.length; i++) {
            if (set.contains(nums2[i]) && !resSet.contains(nums2[i])) {
                resSet.add(nums2[i]);
            }
        }
        
        
        int[] res = new int[resSet.size()];
        int index = 0;
        for (Integer i : resSet) {
            res[index++] = i;
        }
        
        return res;
        
        
        // Method 2 two pointers O(nlogn)
        Arrays.sort(nums1);
        Arrays.sort(nums2);
        
        int i = 0;
        int j = 0;
        
        HashSet set = new HashSet<>();
        while (i < nums1.length && j < nums2.length) {
            if (nums1[i] < nums2[j]) {                 i++;             } else if (nums1[i] > nums2[j]) {
                j++;
            } else {
                set.add(nums1[i]);
                i++;
                j++;
            }
        }
        
        int[] res = new int[set.size()];
        int index = 0;
        for (Integer k : set) {
            res[index++] = k;
        }

        return res;
    }
    
}

 

 

350. Intersection of Two Arrays II

Given two arrays, write a function to compute their intersection.

Example:
Given nums1 = [1, 2, 2, 1], nums2 = [2, 2], return [2, 2].

Note:

  • Each element in the result should appear as many times as it shows in both arrays.
  • The result can be in any order.

Follow up:

  • What if the given array is already sorted? How would you optimize your algorithm?

  • What if nums1‘s size is small compared to nums2‘s size? Which algorithm is better?

  • What if elements of nums2 are stored on disk, and the memory is limited such that you cannot load all elements into the memory at once?

Analysis:

Similar to the above two pointers method, just allows duplicate, then change hashset to a list.

Time complexity: O(nlogn)

Space complexity: O(n)

public class Solution {
    public int[] intersect(int[] nums1, int[] nums2) {
        // corner case
        if (nums1 == null || nums2 == null) {
            return null;
        }
        
        // Two pointers O(nlogn)
        Arrays.sort(nums1);
        Arrays.sort(nums2);
        
        int i = 0;
        int j = 0;
        
        List list = new ArrayList<>();
        while (i < nums1.length && j < nums2.length) {
            if (nums1[i] < nums2[j]) {                 i++;             } else if (nums1[i] > nums2[j]) {
                j++;
            } else {
                list.add(nums1[i]);
                i++;
                j++;
            }
        }
        
        int[] res = new int[list.size()];
        int index = 0;
        for (Integer k : list) {
            res[index++] = k;
        }

        return res;

    }
}

Leetcode 125 Valid Palindrome

Leetcode 125 Valid Palindrome

Given a string, determine if it is a palindrome, considering only alphanumeric characters and ignoring cases.

For example,
"A man, a plan, a canal: Panama" is a palindrome.
"race a car" is not a palindrome.

Note:
Have you consider that the string might be empty? This is a good question to ask during an interview.

For the purpose of this problem, we define empty string as valid palindrome.

In Wiki, Palindrome(回文) means a word, phrase, number, or other sequence of characters which reads the same backward or forward. Allowances may be made for adjustments to capital letters, punctuation, and word dividers.

Analysis:

Basically, a palindrome can be checked by start from both the beginning and the end of the string, comparing them char by char. If they’re the same until all chars being checked, then it’s true. Otherwise, it’s false.

From the above thinking, it should remind us to use two pointers. Fundamentally, we can have two pointers pointing to the start and then end of the string. Move forward and backward at the same time. If they’re all the same, then it’s true, otherwise, its’ false.

Note:

  • empty string is palindrome
  • there exists chars other than characters and digit numbers
  • change all chars to lowercase firstly

When facing specific characters, we just need to ignore them and continue move forward/backward.

Time complexity: O(n)

Space complexity: O(1)

Then comes the code:

public class Solution {
    public boolean isPalindrome(String s) {
        // Two pointers O(n)
        
        if (s == null || s.length() == 0) {
            return true;
        }
        
        s = s.toLowerCase();
        
        int start = 0;
        int end = s.length() - 1;
        
        while (start < end) {
            // Move forward
            if (!Character.isLetterOrDigit(s.charAt(start))) {
                start++;
                continue;
            }
            
            // Move backward
            if(!Character.isLetterOrDigit(s.charAt(end))) {
                end--;
                continue;
            }
            
            if (s.charAt(start) == s.charAt(end)) {
                start++;
                end--;
            } else {
                return false;
            }
        }
        return true;
    }
}

In the code above we used the default method isLetterOrDigit(char c) to check whether a char is a letter or a digit. There’s also other method to check it.

public boolean isValidCharater(char c) {
    return (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9');
}

A easier to understand solution:

public class Solution {
    public boolean isPalindrome(String s) {
        // O(n) O(1)
        
        if (s == null || s.length() == 0) {
            return true;
        }
        
        int left = 0;
        int right = s.length() - 1;
        
        // Change all chars to lowercase
        String str = s.toLowerCase();
        
        while (left = 'a' && c = '0' && c <= '9');
    }
}