leetcode Question: Maximum Gap

Maximum Gap

Given an unsorted array, find the maximum difference between the successive elements in its sorted form.
Try to solve it in linear time/space.
Return 0 if the array contains less than 2 elements.
You may assume all elements in the array are non-negative integers and fit in the 32-bit signed integer range.

Analysis:


It took me a long time figuring out how to solve it, because I was going to a wrong direction after seeing the linear time/space requirement.  To be honest, I was only thinking  of common sorting algorithms (merge, heap, quick).   However, I missed the another type of sorting algorithm ---- Distribution sort (bucket, counting, radix), which happens to be the key of this problem.

We all know that, merge, heap or quick sorting algorithm can achieve no better than O(n Log n) time complexity.  But for linear time requirement, bucket sort, counting sort and radix sort are often good options.

For this specific problem, bucket sort is not a good option because it usually works well on uniform distributions. Otherwise, in each bucket, the insertion sort may cause heavy burden on time complexity. Counting sort, has time complexity O(n + k), where k is the range of the elements. But when k > n^2, it is worse than the common sorting algorithms. So we use the radix sort for solving this problem.

The idea of radix sort is as follows:

  • Sort elements according to each digit (from lower to higher).
  • For each digit, use counting sort.

For example, A = [36 504 79 98 8 55 2 113].

The Radix sorting goes like following steps:

Sort 1st digit:
A = [2, 113, 504, 55, 36, 98, 8, 79]

Sort 2nd digit:
A = [2, 504, 8, 113, 36, 55, 79, 98]

Sort 3rd digit:
A = [2, 8, 36, 55, 79, 98, 113, 504]

Done.


To sort array according to each digit, counting sort is used. Note that, we only need to have a array of size 10 to store the frequencies of elements. This is because we only consider and sort a single digit in each iteration of Radix sort.

The general form of counting sort is:
(1) Count the frequencies of each elements.  (count[a[i]] ++, this also considers the duplicates)
(2) Get the index of each number in the output array. (count[i]+= count[i-1])
(3) Put numbers in order. (output[count[a[i]] = a[i], count[a[i]]-- to handle the duplicates)

For radix sort, there is minor modifications, details see the code below.


Code(C++):

class Solution {
public:
    int getMax(vector<int> num){
        int m = INT_MIN;
        for (int i=0;i<num.size();i++){
            m = max(m,num[i]);
        }
        return m;
    }
    
    void countSort(vector<int> &num, int nd){
        int n = num.size();
        vector<int> output(n,0);
        vector<int> count(10,0);
 
        for (int i = 0; i < n; i++){
            count[ (num[i]/nd)%10 ]++;
        }
 
        for (int i = 1; i < 10; i++){
            count[i] += count[i - 1];
        }
 
        for (int i = n - 1; i >= 0; i--){
            output[ count[(num[i]/nd)%10] - 1] = num[i];
            count[ (num[i]/nd)%10 ]--;
        }
 
        for (int i = 0; i < n; i++){
            num[i] = output[i];
        }
    }

    void radixsort(vector<int> &num){
         int max_n = getMax(num);
         for (int nd = 1; max_n/nd > 0; nd *= 10){
             countSort(num, nd);
         }
    }
    
    int maximumGap(vector<int> &num) {
        if (num.size()<2){
            return 0;
        }
        radixsort(num);
        int res = abs(num[1] - num[0]);
        for (int i=2;i<num.size();i++){
            if (num[i]-num[i-1]>res){
                res = abs(num[i] - num[i-1]);
            }
        }
        return res;
        
    }
};

Code(Python):

class Solution:
    # @param num, a list of integer
    # @return an integer
    
    def countsort(self, num, nd):
        count = [0]*10
        n = len(num)
        for i in xrange(0,n):
            count[ (num[i]/nd) %10] += 1
            
        for i in xrange(1,10):
            count[i] += count[i-1]
        
        output = [0]*n
        for i in xrange(n-1,-1,-1):
            output[count[ (num[i]/nd)%10 ] - 1 ] = num[i]
            count[ (num[i]/nd)%10 ] -= 1
        
        return output
    
    def radixsort(self, num):
        max_n = max(num)
        nd = 1
        while max_n / nd > 0:
            num = self.countsort(num, nd)
            nd = nd * 10
        return num
        
    def maximumGap(self, num):
        if len(num) < 2:
            return 0
        num = self.radixsort(num)
        res = abs(num[1] - num[0])
        for i in xrange(2,len(num)):
            res = max(res, abs(num[i] - num[i-1]))
        return res
        
        

leetcode Question: Find Peak Element

Find Peak Element

A peak element is an element that is greater than its neighbors.
Given an input array where num[i] ≠ num[i+1], find a peak element and return its index.
The array may contain multiple peaks, in that case return the index to any one of the peaks is fine.
You may imagine that num[-1] = num[n] = -∞.
For example, in array [1, 2, 3, 1], 3 is a peak element and your function should return the index number 2.
Note:
Your solution should be in logarithmic complexity.

Analysis:

It is required to have log(N) complexity, for the single array, binary search is usually considered since it satisfied the log(N) requirement.
Be careful with the boundary conditions, it is a pretty simple problem.


Code(C++):

class Solution {
public:
    void fp(int st, int ed, const vector<int> &num, int &idx){
        if (st > ed || idx != -1){
            return;
        } else {
            int mid = st + (ed - st)/2;
            
            if (mid == num.size()-1 && num[mid]>num[mid-1]){
                idx = mid;
                return;
            }
            if (mid == 0 && num[mid]>num[mid+1]){
                idx = mid;
                return;
            }
            if (num[mid]>num[mid-1] && num[mid]>num[mid+1]){
                idx = mid;
                return;
            } 
            fp(st,mid-1,num, idx);
            fp(mid+1,ed,num, idx);
        }
    }

    int findPeakElement(const vector<int> &num) {
        if (num.size() == 1){
            return 0;
        }
        int idx = -1;
        fp(0, num.size()-1,num,idx);
        return idx;
    }
};

Code(Python):

class Solution:
    # @param num, a list of integer
    # @return an integer
    
    idx = -1
    def findPeakElement(self, num):
        if len(num) == 1:
            return 0
        self.fp(0, len(num)-1, num)
        return self.idx
        
    def fp(self, st, ed, num):
        if st > ed or self.idx != -1:
            return
        else:
            mid = st + (ed - st)/2;
            if mid == len(num)-1 and num[mid]>num[mid-1]:
                self.idx = mid
                return
            if mid == 0 and num[mid]>num[mid+1]:
                self.idx = mid
                return
            if num[mid]>num[mid-1] and num[mid]>num[mid+1]:
                self.idx = mid
                return
            self.fp(st,mid-1,num)
            self.fp(mid+1,ed,num)
        

leetcode Question: Intersection of Two Linked Lists

Intersection of Two Linked Lists

Write a program to find the node at which the intersection of two singly linked lists begins.

For example, the following two linked lists:
A:          a1 → a2
                   ↘
                     c1 → c2 → c3
                   ↗            
B:     b1 → b2 → b3
begin to intersect at node c1.

Notes:
  • If the two linked lists have no intersection at all, return null.
  • The linked lists must retain their original structure after the function returns.
  • You may assume there are no cycles anywhere in the entire linked structure.
  • Your code should preferably run in O(n) time and use only O(1) memory.

Analysis:

Consider the case that two list has equal length, the problem became so easy: only two pointers are needed.  Scan from the start of each list, check if the node are the same. Problem solved !

However, just like the example showed in the question, we need to handle the case when the two list are not equal in length.  What to do then?  Let's make them equal !
(1) Get the length of list A, say n_a.
(2) Get the length of list B, say n_b.
These two steps will take O(n) time. (n = n_a + n_b)
(3) Set two pointers. Make the pointer of longer list abs(n_a-n_b) steps forward.
(4) Scan the two list until find the intersection, or to the end of list.
This step will take O(n) time.

Totally, time complexity is O(n), space complexity is O(1).


Code(C++):

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        int n1 = 0; //length of headA
        int n2 = 0; //length of headB
        ListNode * a1 = headA; 
        ListNode * a2 = headB;
        
        while (a1){
            n1++;
            a1 = a1->next;
        }
        while (a2){
            n2++;
            a2 = a2->next;
        }
        
        a1 = headA;
        a2 = headB;
        
        while (n1>0 && n2>0){
            if (n1>n2){
                n1--;
                a1 = a1->next;
            }
            if (n2>n1){
                n2--;
                a2 = a2->next;
            }
            if (n2 == n1){
                if (a1 == a2){
                    return a1;
                }else{
                    a1 = a1->next;
                    a2 = a2->next;
                    n1--;
                    n2--;
                }
            }
        }
        return NULL;
    }
};


Code(Python):

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    # @param two ListNodes
    # @return the intersected ListNode
    def getIntersectionNode(self, headA, headB):
        a = headA
        b = headB
        n1 = 0
        n2 = 0
        
        while a is not None:
            a  = a.next
            n1 += 1
        while b is not None:
            b  = b.next
            n2 += 1
            
        a = headA
        b = headB
        
        while n1 > 0 and n2 > 0:
            if n1 > n2:
                a = a.next
                n1 -= 1
            if n2 > n1:
                b = b.next
                n2 -= 1
            if n1 == n2:
                if a == b:
                    return a
                else:
                    a = a.next
                    b = b.next
                    n1 -= 1
                    n2 -= 1
        return None
        

leetcode Question: Min Stack

Min Stack:

Design a stack that supports push, pop, top, and retrieving the minimum element in constant time.
  • push(x) -- Push element x onto stack.
  • pop() -- Removes the element on top of the stack.
  • top() -- Get the top element.
  • getMin() -- Retrieve the minimum element in the stack.

Analysis:

There are several ways to solve this problem.
(1) Use an extra stack to store the minimum value. The space is O(n), time O(1)
(2) Use a variable to store the minimum value. The time is O(n), space O(1)

Note that, in the python code, a little modification is needed to pass the OJ test.
Just using two stacks is not satisfied with the memory requirement.
So, the min stack stores [min_val, count] instead of each min_val.
e.g.,
Push into Stack:
st     min_st
2      [2,1]

st     min_st
0      [0,1]
2      [2,1]

st     min_st
3    
0      [0,1]
2      [2,1]

st     min_st
0
3    
0      [0,2]
2      [2,1]

Pop:
st     min_st
3    
0      [0,1]
2      [2,1]

st     min_st
0      [0,1]
2      [2,1]

st     min_st
2      [2,1]




Code(C++):


class MinStack {
    deque<int> st;
    int minVal;
public:
    void push(int x) {
        if (st.empty() || x<minVal){
            minVal = x;
        }
        st.push_front(x);
    }

    void pop() {
        if (st.front() == minVal){
            st.pop_front();
            minVal=INT_MAX;
            for (deque<int>::iterator it = st.begin();it!=st.end();it++){
                minVal = min(minVal,*it);
            }
        }else{
            st.pop_front();
        }
        
    }

    int top() {
        return st.front();
    }

    int getMin() {
        return minVal;
    }
};


Code(Python):

class MinStack:
    # @param x, an integer
    # @return an integer
    def __init__(self):
        self.l_num = []
        self.minval = []
    
    def push(self, x):
        if len(self.l_num) == 0 or len(self.minval) == 0:
            self.minval.append([x,1])
        else:
            if x < self.getMin():
                self.minval.append([x,1])
            elif x == self.getMin():
                self.minval[-1][1] += 1
        self.l_num.append(x)
            
    # @return nothing
    def pop(self):
        if self.l_num[-1] == self.minval[-1][0]:
            self.l_num.pop(-1)
            if (self.minval[-1][1]>1):
                self.minval[-1][1] -= 1
            else:
                self.minval.pop(-1)
        else:
            self.l_num.pop(-1)
            
        
    # @return an integer
    def top(self):
        return self.l_num[-1]

    # @return an integer
    def getMin(self):
        return self.minval[-1][0]
        


leetcode Question: Single Number II

Single Number II

Given an array of integers, every element appears three times except for one. Find that single one.
Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?

Analysis:

The general idea of this problem, is to consider all the numbers bit by bit, count the occurrence of '1' in each bit. To get the result, check if the number can be divided by 3 (mod 3 = 0), put '0' if true and '1' otherwise.

(Idea coming from the internet)
Since we know that XOR operation can be used for testing if 1 bit occurs twice, in other words, for a single bit, if 1 occurs twice, it turns to 0.
Now we need a 3-time criteria for each bit, by utilizing the bit operations.
This 3-time criteria needs every bit turns to 0 if  '1' occurs three times.

If we know on which bits '1' occurs twice, and also know on which bits '1' occurs 1-time, a simple '&' operation would result in the bit where '1' occurs three times. Then we turn these bit to zero, would do well for this problem.

(1). Check bits which have 1-time '1', use the XOR operation.
(2). Check bits which have 2-times '1's, use current 1-time result & current number.
(3). Check bits which have 3-times '1's, use '1-time' result & '2-times' result
(4). To turn 3-times bits into 0:   ~(3-times result) & 1-time result
                                                     ~(3-times result) & 2-times result
   
E.g.,We have numbers:  101101,   001100, 101010
To count the occurrence of 1's:
101101
001100
101010
count:  {2,0,3,2,1,1}

Denote:
t1: bit=1 if current bit has 1-time '1'
t2: bit=1 if current bit  has 2-times '1'
t3: bit=1 if current bit  has 3-times '1'

Result:
t1 = 000011, t2 = 100100, t3 = 001000



Initialization: t1 = 000000, t2=000000, t3 = 000000
(1) 101101
t1 = 101101  (using XOR)
t2 = 000000
t3 = 000000

(2)001100
% Current 2 times bits (t2) and NEW 2 times bits coming from 1 time bits and new number.
t2 = t2 | 001100 & t1 =  001100 & 101101 = 001100
t1 = t1 XOR 001100 = 100001
t3 = t2 & t1 = 000000

(3)101010
t2 = t2 | (101010 & t1) = t2 | (101010 & 100001) = 101100
t1 = t1 XOR 101010 = 100001 XOR 101010 = 001011

t3 = t1 & t2 = 001000

%Turn 3-time bits into zeros
t1 = t1 & ~t3 = 000011
t2 = t2 & ~t3 = 100100



Code(C++):


class Solution {
public:
    int singleNumber(int A[], int n) {
        int t1 = 0;
        int t2 = 0;
        int t3 = 0;
        
        for (int i = 0; i < n; i++){
            t1 = t1 ^ A[i];
            t2 = t2 | ((t1^A[i]) & A[i]);
            t3 = ~(t1 & t2);
            t1 = t1 & t3;
            t2 = t2 & t3;
        }
        
        return t1;
        
    }
};

Code(Python):


class Solution:
    # @param A, a list of integer
    # @return an integer
    def singleNumber(self, A):
        t1 = 0;
        t2 = 0;
        t3 = 0;
        for a in A:
            t2 = t2 | (t1 & a);
            t1 = t1 ^ a;
            t3 = ~(t1 & t2);
            t1 = t1 & t3;
            t2 = t2 & t3;
        return t1;

leetcode Quesion: Maximum Product Subarray

Maximum Product Subarray


Find the contiguous subarray within an array (containing at least one number) which has the largest product.

For example, given the array [2,3,-2,4],
the contiguous subarray [2,3] has the largest product = 6.


Analysis:

Brutal force method will take O(n^2) time complexity, which is not acceptable.
Since it requires the "largest" product in an array, it is common to consider the DP(dynamic programming) method. And also since O(n^2) is NOT acceptable, there might be an O(n) solution.

So, given a whole scan , how to find the maximum product?
Note that, we need to consider two cases:
(1) negative numbers
          Store the minimum product to handle the case that new element < 0. Because if current element < 0, the product of two negative numbers (new element, and minimum product before the new element) become positive.
(2) zeros
        When meets zero, current max and min product become 0, new search is needed from the next element.

Therefore,  we can write down to function to store both + and - products:

max_product = max{A[i]*min_product (when A[i]<0),  A[i]*max_product (when A[i]>0),  A[i] (when 0 occurs before A[i]) }.

min_product = min{A[i]*min_product,  A[i]*max_product,  A[i] }.

Because current sequence might start from any element, to get the final result, we also need to store the max product after each iteration "res = max(res, maxp);".



Code(C++):


class Solution {
public:
    int maxProduct(int A[], int n) {
        int res = A[0];
        int maxp = A[0];
        int minp = A[0];
        for (int i=1;i<n;i++){
            int tmpmax = maxp;
            int tmpmin = minp;
            maxp = max(max(tmpmax*A[i],tmpmin*A[i]),A[i]);
            minp = min(min(tmpmax*A[i],tmpmin*A[i]),A[i]);
            res = max(maxp,res);
        }
        return res;
    }
};

Code(Python):


class Solution:
    # @param A, a list of integers
    # @return an integer
    def maxProduct(self, A):
        res = A[0]
        minp = A[0]
        maxp = A[0]
        for a in A[1:]:
            tmp_maxp = maxp
            tmp_minp = minp
            maxp = max(max(tmp_maxp*a, tmp_minp*a), a)
            minp = min(min(tmp_maxp*a, tmp_minp*a), a)
            res = max(res, maxp)
        return res
            
        

leetcode Question: Find Minimum in Rotated Sorted Array II

Find Minimum in Rotated Sorted Array II


Suppose a sorted array is rotated at some pivot unknown to you beforehand.

(i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2).

Find the minimum element.

The array may contain duplicates.


Analysis:
The solution is similar to the previous question (here), only difference is we can 'skip' the duplicates before determining if the sub array is ordered.


Code(C++):

class Solution {
public:
    void bs(vector<int> &num, int st,int ed, int &res){
        if (st>ed){ return; }
        else {
            int mid = st+(ed-st)/2; //get middle index
            
            while (num[mid]==num[ed] && mid!=ed) {ed--;}
            while (num[mid]==num[st] && mid!=st) {st++;}
            if (num[mid]<num[ed] || mid==ed){  // right part ordered
                res = min(res,num[mid]); //get right part min
                bs(num,st,mid-1,res); //search left part
            } else {  //right part unordered
                res = min(res,num[st]); //get left part min
                bs(num, mid+1, ed,res); //serch right part
            }
        }
    }
    int findMin(vector<int> &num) {
        int n = num.size();
        int res = num[0];
        bs(num,0,n-1,res);
        return res;
    }
};


Code(Python):

class Solution:
    # @param num, a list of integer
    # @return an integer
    def bs(self, num, st, ed, res):
        if st > ed:
            return res
        else:
            mid = st + (ed - st)/2
            while num[mid]==num[ed] and mid!=ed:
                ed -= 1
            while num[mid]==num[st] and mid!=st:
                st += 1
            if num[mid] < num[ed] or mid == ed:
                res = min(res, num[mid])
                return self.bs(num, st, mid-1, res)
            else:
                res = min(res, num[st])
                return self.bs(num, mid+1, ed, res)
        
    def findMin(self, num):
        n = len(num)
        res = num[0]
        return self.bs(num, 0, n-1, res)

leetcode Question: Find Minimum in Rotated Sorted Array

Find Minimum in Rotated Sorted Array

Suppose a sorted array is rotated at some pivot unknown to you beforehand.

(i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2).

Find the minimum element.

You may assume no duplicate exists in the array.


Analysis:


In a sorted array, the minimum is the first element. Now the array has been rotated, so we need to search the minimum element. Binary search is usually a efficient way dealing with such problems where the "sub" array has the similar structure of the "parent" array.

In this problem, there is only 1 rotation, so that there are only limited cases when we split the array using the mid-element:
 1. the right part is ordered (A[mid] < A[ed])
 2. the right  part is unordered (A[mid] > A[ed])
 Some might say that what about the left part of the array? Note that there is only 1 rotation, which indicates that if right part is unordered, the left part of array must be ordered.

Considering the above two cases, finding the minimum is now becoming a simple binary search with slight modifications. Details can be seen in the following code.

Code(C++):


class Solution {
public:
    void bs(vector<int> &num, int st,int ed, int &res){
        if (st>ed){ return; }
        else {
            int mid = st+(ed-st)/2; //get middle index
            if (num[mid]<num[ed]){  // right part ordered
                res = min(res,num[mid]); //get right part min
                bs(num,st,mid-1,res); //search left part
            } else {  //right part unordered
                res = min(res,num[st]); //get left part min
                bs(num, mid+1, ed,res); //search right part
            }
        }
    }
    int findMin(vector<int> &num) {
        int n = num.size();
        int res = num[0];
        bs(num,0,n-1,res);
        return res;
    }
};

Code(Python):


class Solution:
    # @param num, a list of integer
    # @return an integer
    def bs(self, num, st, ed, res):
        if st > ed:
            return res
        else:
            mid = st + (ed - st)/2
            if num[mid] < num[ed]:
                res = min(res, num[mid])
                return self.bs(num, st, mid-1, res)
            else:
                res = min(res, num[st])
                return self.bs(num, mid+1, ed, res)
        
    def findMin(self, num):
        n = len(num)
        res = num[0]
        return self.bs(num, 0, n-1, res)

[NEW] LeetCode Online Judge Questions/Answer List

Note:

This post listed the questions in the same order of leetcode website. 
The links to the answer posts is added for your convenience.

I revisited all the questions again and also have modified/updated analysis and code for many of them. Several easier implementations or easier understanding analysis have been added. 



NEW!!!~ I am starting to add Python Code for the leetcode problems.  





LeetCode Online Judge Questions/Answer List

  • Single Number II
  • Scramble String   (Difficlut problem, 3D DP might work)


leetcode Question: Sort List

leetcode Question: Sort List

Sort a linked list in O(n log n) time using constant space complexity.


Analysis:

From the post "Common Sorting Algorithms", we know that the sorting algorithms which have O(n log n) complexity are merge sort and quick sort. So in this problem, we can use merge sort to handle!

Different from array data, this problem requires good understanding of linked list operations, e.g., split, merge.  Before doing this problem, I suggest you first check out the problem "Merge Two Sorted List" and "Linked List Cycle", and also the merge sort algorithm itself. Then the problem becomes pretty straightforward.

Like the merge sort, we can do recursively:
(1) Split the list (slow fast pointers)
(2) sort the first part (merge sort)
(3) sort the second part (merge sort)
(4) merge the two parts (merge two sorted lists)

See the code below for details. In this code, the pointer to the pointer (reference pointer) is used, note that to get the pointer where "ptrRef" points, we can use "*ptrRef".



Code:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    // Merge two sorted list (save as the leetcode Question 54: Merge Two Sorted Lists)
    ListNode* sortedMerge(ListNode* l1, ListNode* l2){
        ListNode* res = new ListNode(0);
        ListNode* current = res;
        while (true){
            if (!l1){
                current->next = l2;
                break;
            }
            if (!l2){
                current->next = l1;
                break;
            }
            if (l1->val < l2->val){
                current->next = l1;
                l1 = l1->next;
            }else{
                current->next = l2;
                l2 = l2->next;
            }
            current = current->next;
        }
        return res->next;
    }

    // Split a list into two parts, using slow/fast pointers
    void split(ListNode* head, ListNode** aRef, ListNode** bRef){
        ListNode* slow;
        ListNode* fast;
        if (head==NULL || head->next==NULL){
            *aRef = head;
            *bRef = NULL;
        }else{
            slow = head;
            fast = head;
            while (fast!=NULL && fast->next!=NULL){
                fast = fast->next->next;
                if (fast==NULL){break;} // this is important
                slow = slow->next;
            }
            *aRef = head;
            *bRef = slow->next;
            slow->next=NULL;
        }
    }

    // MergeSort LinkedList
    void mergeSort(ListNode** headRef){
        ListNode* head = *headRef;
        ListNode* a;
        ListNode* b;
        
        if (head==NULL || head->next==NULL){
            return;
        }
        
        split(head,&a,&b);   //split the list
        
        mergeSort(&a);       //sort the first part
        mergeSort(&b);       //sort the second part    
        
        *headRef = sortedMerge(a,b);    // merge two sorted part
    }

    //main function
    ListNode *sortList(ListNode *head) {
        mergeSort(&head);
        return head;
    }
};

leetcode Questions: Reverse Words in a String


Reverse Words in a String


Given an input string, reverse the string word by word.
For example,
Given s = "the sky is blue",
return "blue is sky the".
Clarification:
  • What constitutes a word?
    A sequence of non-space characters constitutes a word.
  • Could the input string contain leading or trailing spaces?
    Yes. However, your reversed string should not contain leading or trailing spaces.
  • How about multiple spaces between two words?
    Reduce them to a single space in the reversed string.

Analysis:

The clarification is very important, during the interview, one should think of these points without hint, and then implement the algorithm.

By checking the clarifications, the programming is straightforward, here provides a simple version which uses buffer strings:
(1)Loop from start to the end of the string:
          (a) if current char is space and word string is empty, continue.
          (b) if current char is space but word string is NOT empty, which means we meet the end of word, then output the word, reset the word, continue.
          (c) if current char is non-space char, add this char to the word string, continue
(2)Handle the last word:
      (a) if the last word is empty, which means the input is empty, or the input has only spaces, or the last char/chars are spaces.  Then just remove the last space in the output string and return.
      (b) if the last word is not empty, add the last word to the front of the output string, then remove the last space in the output string and return.
    

Code (C++):


class Solution {
public:
    void reverseWords(string &s) {
        string word; //tmp string to store each word
        string res; // result string
        int i=0;
        while (i<s.size()){
            if (char(s[i])==' ' && word.empty()){i++;continue;} //multiple spaces
            if (char(s[i])==' ' && !word.empty()){ //first space after a word
                res = word+" "+ res; //store the word
                word=""; //reset the word
                i++; continue;
            }
            if (char(s[i])!=' '){word=word+char(s[i]);i++; continue;} //non-space chars 
        }
        
        if (!word.empty()){ //last word
            s = word+" "+res;
        }else{
            s = res;
        }
        s = s.substr(0,s.size()-1); //eliminate the last space
    }
};



Code (Python):

class Solution:
    # @param s, a string
    # @return a string
    def reverseWords(self, s):
        res = ""    # result string
        word = ""   # single word string
        for ch in s:
            if (ch!=' '):
                word+=ch
            if (ch==' '):
                if (len(word)!=0):
                    if (res!=""):   # add space between words
                        res = ' ' + res
                    res = word + res
                    word = ""
               
        if (len(word)!=0):  #handle the final word
            if (res!=""):
                res = ' ' + res
            res = word + res
            
        return res
                    
                
                
        

[Re-view] Tree Traversal (PreOrder, InOrder, PostOrder): Recursion and Non-Recursion(Iteration)

[Re-view] Tree Traversal (PreOrder, InOrder, PostOrder):  Recursion and Non-Recursion(Iteration)


Introduction


In this post, I would like to talk one important algorithm---- Tree Traversal. Tree traversal is a basic but crucial concept in data structure and algorithm, which is also very hot in interviews. In this post, I assume that you have already had the idea of "what is binary tree?", "what is tree traversal?", and "what is stack?". I will focus on Recursive and Non-Recursive traversal, for PreOrder, InOrder, PostOrder, and Level Order of binary tree. Algorithm description with GIF animation are provided along with the C++ implementations. The code can be run and tested in leetcode online judge as well.

Actually the "three order" traversal is easily to memorize in this way:  Where is the root? When the root is in the first place to be visited (root->left->right), then it is "pre" order, when the root is in the middle to be visited (left->root->right), then it is "in" order, and when the root is last to be visited, it is "post" order.

PreOrder Traversal:

Description:
PreOrder traversal is according to the root, left and right order traversing the binary tree.

Recursive traversal is straightforward:  we first visit the root node, then traverse its left child, then its right child.

Non-Recursive traversal is to ulitize the data structure stack. There are three steps for this algorithm:
(1) Initialize the stack. Push the root node into stack.
(2) While the stack is not empty do:
        (a) Pop the top node from the stack.
        (b) Store the top node
        (c) Push the top node's right child into stack
        (d) Push the top node's left child into stack
(3) Output the stored sequence.

Animation(non-recursive):


Code (PreOrder Traversal):
/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
      // preorder traversal: recursion 
    void pre_recur(TreeNode* root, vector<int> &res){
        if (!root){         //if null node, return
            return;
        }else{
            res.push_back(root->val); // traverse root child
            if (root->left){    
                pre_recur(root->left,res); //traverse left child
            }
            if (root->right){
                pre_recur(root->right,res); //traverse right child
            }
        }
    }
    
    // preorder traversal: non-recursion
    void pre_norecur(TreeNode* root,vector<int> &res){
        stack<TreeNode*> st;
        st.push(root);   //initialize stack
        
        TreeNode* tmp;
        while (!st.empty()){
            tmp=st.top();  //get the top node in stack 
            st.pop();
            res.push_back(tmp->val); //store the root value
            if (tmp->right){st.push(tmp->right);} //push right child into stack 
            if (tmp->left){st.push(tmp->left);} //push left child into stack 
        }
    }
    
    vector<int> preorderTraversal(TreeNode *root) {
        vector<int> res;
        if (!root){return res;}
        
        //pre_recur(root,res);   //recursive traversal 
        pre_norecur(root,res); //non-recursive traversal
        return res;
    }
};



InOrder Traversal:

Description:
InOrder traversal is according to the left, root, and right order traversing the binary tree.

Recursive traversal is straightforward:  we first traverse the left child, then visit the root node, then traverse the right child.

Non-Recursive traversal is to ulitize the data structure stack. There are three steps for this algorithm:
(1) Initialize the stack. Set root as the current node. Push the current node into stack.
(2) Loop until finished (while true):
        (a) If current has left child:
                (i)Push left child into stack.
                (ii)Current node = current node's left child 
        (b) If current has NO left child:
                (i)If stack is empty: exit
                (ii)If stack is NOT empty:
                      Pop the top node in the stack.
                      Store the top node for output.
                      Set current node = top node's right child.              
(3) Output the stored sequence.

Animation(non-recursive):
Code (InOrder Traversal):
/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    // inorder traversal: recursion 
    void in_recur(TreeNode* root, vector<int> &res){
        if (!root){         //if null node, return
            return;
        }else{
            if (root->left){in_recur(root->left,res);} //traverse left child
            res.push_back(root->val); // traverse root child
            if (root->right){in_recur(root->right,res);} //traverse right child
        }
    }
    
    // inorder traversal: non-recursion
    void in_norecur(TreeNode* root,vector<int> &res){
        stack<TreeNode*> st;
        while (true){
            if (root){  // keep pushing the left child of current node
                st.push(root);
                root=root->left;
            }else{
                if (!st.empty()){   
                    TreeNode* top = st.top();   //pop the top node in the stack
                    st.pop();
                    res.push_back(top->val);    //output the top node
                    root=top->right;            //set current node=right child of top node
                }else{
                    break;  //if the stack is empty, then exit
                }
            }
        }
    }

    vector<int> inorderTraversal(TreeNode *root) {
       vector<int> res;
        if (!root){return res;}
        //in_recur(root,res);   //recursive traversal 
        in_norecur(root,res); //non-recursive traversal
        return res;
    }
};


PostOrder Traversal:

Description:
PostOrder traversal is according to the left, right, and root order traversing the binary tree.

Recursive traversal is straightforward:  we first traverse the left child, then traverse the right child, then visit the root node.

Non-Recursive traversal is to ulitize the data structure stack. Two stacks is used in this algorithm. Stack 2 is used to store the result. There are three steps:
(1) Initialize the stack. Push the root node into stack.
(2) While the stack is not empty do:
        (a) Pop the top node from the stack 1.
        (b) Push the top node into stack 2.
        (c) Push the top node's left child into stack 1.
        (d) Push the top node's right child into stack 1.
(3) Pop all the nodes in Stack 2 to get the result.

Animation(non-recursive):
Code (PostOrder Traversal):
/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    // postorder traversal: recursion 
    void post_recur(TreeNode* root, vector<int> &res){
        if (!root){         //if null node, return
            return;
        }else{
            if (root->left){    
                post_recur(root->left,res); //traverse left child
            }
            if (root->right){
                post_recur(root->right,res); //traverse right child
            }
            res.push_back(root->val); // traverse root child
        }
    }
    
    // postorder traversal: non-recursion
    void post_norecur(TreeNode* root,vector<int> &res){
        stack<TreeNode*> st1;
        stack<TreeNode*> st2;
        st1.push(root);   //initialize stack one
        
        TreeNode* tmp;
        while (!st1.empty()){
            tmp=st1.top();  //get the top node in stack 1
            st1.pop();  
            st2.push(tmp);  //push into stack 2
            if (tmp->left){st1.push(tmp->left);} //push left child into stack 1
            if (tmp->right){st1.push(tmp->right);} //push right child into stack 1
        }
        
        while (!st2.empty()){  //output the stack 2
            tmp=st2.top();
            st2.pop();
            res.push_back(tmp->val);
        }
        
    }

    vector<int> postorderTraversal(TreeNode *root) {
        vector<int> res;
        if (!root){return res;}
        
        //post_recur(root,res);   //recursive traversal 
        post_norecur(root,res); //non-recursive traversal
        return res;
    }
};









leetcode Question: Candy

Candy

There are N children standing in a line. Each child is assigned a rating value.
You are giving candies to these children subjected to the following requirements:
  • Each child must have at least one candy.
  • Children with a higher rating get more candies than their neighbors.
What is the minimum candies you must give?

Analysis:

Scan the rating array from left to right and then from right to left. In every scan just consider the rising order (l->r: r[i]>r[i-1] or r->l: r[i]>r[i+1]), assign +1 candies to the rising position.
The final candy array is the maximum (max(right[i],left[i])) in each position.
The total candies is the sum of the final candy array.

The time complexity is O(n).

Code:


class Solution {
public:
    int getC(vector<int> &r){
        vector<int> lc(r.size(),1);
        vector<int> rc(r.size(),1);
        int res=0;
        for (int i=1;i<lc.size();i++){
            if (r[i]>r[i-1]){
                lc[i]=lc[i-1]+1;
            }
        }
        for (int i=rc.size()-2;i>=0;i--){
            if (r[i]>r[i+1]){
                rc[i]=rc[i+1]+1;
            }
        }
        for (int i=0;i<r.size();i++){
            res+=max(lc[i],rc[i]);
        }
        return res;
    }
    
    int candy(vector<int> &ratings) {
        return getC(ratings);
    }
};

leetCode Question: Word Ladder II

Word Ladder II

Given two words (start and end), and a dictionary, find all shortest transformation sequence(s) from start to end, such that:
  1. Only one letter can be changed at a time
  2. Each intermediate word must exist in the dictionary
For example,
Given:
start = "hit"
end = "cog"
dict = ["hot","dot","dog","lot","log"]
Return
  [
    ["hit","hot","dot","dog","cog"],
    ["hit","hot","lot","log","cog"]
  ]
Note:
  • All words have the same length.
  • All words contain only lowercase alphabetic characters.

Analysis:

This is NOT an easy problem because of the time and memory requirements.

(1) From the previous Word Ladder I, we know that Breadth First Search is a better way than the DFS.

(2) The requirement of this question is to output ALL the shortest path, which means if we find one path using the BFS, then all the other shortest paths must also in this level, so the search will stop once this level ends.

(3) We need to output the exact path, so we need one way to store the paths.

(4) For each words in the BFS queue, we still need to use the previous way to generate the valid words in the dicts (from 1st to last, change every char from 'a' to 'z' ).

(5) Duplicates is permitted within a level. e.g.,
      hem -> hex -> tex -> ted
      hem->  tem -> tex -> ted,  are all valid paths.
      Draw this into a tree structure:
                        hem
                       /       \
                    hex    tem
                      |        |
                    tex     tex
                      |        |
                    ted     ted
     A solution is to erase all the words in the previous level, instead of erasing words for each word in the level.

(6) Some experiences that I tried and failed:
     (a). Use a big map to store valid words for each dict(map<string, vector<string> >).  Failed: Memory Limit Exceeds.
     (b). Use the struct as Word Ladder I, add one "pre" string member to store the path. Failed: Memory Limit Exceeds.
     (c). Use a vector to store the path. Failed: either time limit exceeds, or failed to track all the paths.
     (d). Use bidirectional BFS. Failed: complex to track all the paths.


(7) Use a map to store and retrieve the paths. map<string, vector<string> >, stores all the previous strings for current string. Retrieval of the path will need recursion.

(8) Because we have the map storing the paths, the standard queue is not needed. Because what we do now is searching each level (see the tree above), once we found the path, still need to finish that level and apply the output. So two "queue" can be used, one stores the current level words, one stores the next level words. The next level words are generated from the current level. During the generation of valid words, path can be stored at the same time. When the next level words are all generated, if the end string is included, we can output the paths, otherwise, we can erase the words in current level, and search the next level. This erasing step is helping reduce the dict, and eliminate the case that a cycle exists in the path.

(9) The dict in the last test case contains about 3,000 words.


Code:


class Solution {
public:
    unordered_map<string,vector<string> > mp; // result map
    vector<vector<string> > res;
    vector<string> path;
    
    void findDict2(string str, unordered_set<string> &dict,unordered_set<string> &next_lev){
        int sz = str.size();
        string s = str;
        for (int i=0;i<sz;i++){
            s = str;
            for (char j = 'a'; j<='z'; j++){
                s[i]=j;
                if (dict.find(s)!=dict.end()){
                    next_lev.insert(s);
                    mp[s].push_back(str);
                }
            }
        }
    }
    
    void output(string &start,string last){
        if (last==start){
            reverse(path.begin(),path.end());
            res.push_back(path);
            reverse(path.begin(),path.end());
        }else{
            for (int i=0;i<mp[last].size();i++){
                path.push_back(mp[last][i]);
                output(start,mp[last][i]);
                path.pop_back();
            }
        }
    }
    
    vector<vector<string>> findLadders(string start, string end, unordered_set<string> &dict) {
        mp.clear();
        res.clear();
        path.clear();
        
        dict.insert(start);
        dict.insert(end);
        
        unordered_set<string> cur_lev;
        cur_lev.insert(start);
        unordered_set<string> next_lev;
        path.push_back(end);
        
        
        while (true){
            for (auto it = cur_lev.begin();it!=cur_lev.end();it++){dict.erase(*it);} //delete previous level words
            
            for (auto it = cur_lev.begin();it!=cur_lev.end();it++){  //find current level words
                findDict2(*it,dict,next_lev);
            }
            
            if (next_lev.empty()){return res;}
            
            if (next_lev.find(end)!=dict.end()){ //if find end string
                output(start,end);
                return res;
            }
            
            cur_lev.clear();
            cur_lev = next_lev;
            next_lev.clear();
        }
        return res;    
    }
};

leetcode Question: Word Break II

Word Break II

Given a string s and a dictionary of words dict, add spaces in s to construct a sentence where each word is a valid dictionary word.
Return all such possible sentences.
For example, given
s = "catsanddog",
dict = ["cat", "cats", "and", "sand", "dog"].
A solution is ["cats and dog", "cat sand dog"].

Analysis:


For the "Return all" problems, usually DFS or BFS will work well.
In this problem, a DFS with a simple cutting edge condition will pass all the test cases.
However, I think definitely my solution is not an optimal one. Better idea will be updated later.
For the first two trail, I used different DFS scheme but all failed the last test case. (see the commented part of the code below.)

It seems that the last test case will cause the "time exceed" error:
Last executed input:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab", ["a","aa","aaa","aaaa","aaaaa","aaaaaa","aaaaaaa","aaaaaaaa","aaaaaaaaa","aaaaaaaaaa"]
All the searching rounds in this case are not needed because this string has no solutions (last "b" cannot match any word in dict).

So, according to the idea of the previous question word break I, after get the index array mp, a initial test is provided and if there is no possible solution, no searching is needed and return the empty vector.


Code:

class Solution {
public:

    /*void dfs_0(string &s, int st, vector<int> &sp, vector<string> &res,unordered_set<string> &dict){
        if (st>=s.size()){
            string str=s;
            for (int i=0;i<sp.size();i++){
                str.insert(sp[i]+i," ");
            }
            res.push_back(str);
        }else{
            for (int ed = st; ed<s.size();ed++){
                if (dict.find(s.substr(st,ed-st))!=dict.end()){
                    sp.push_back(ed+1);
                    DFS(s,ed+1,sp,res,dict);
                    sp.pop_back();
                }
            }
        }
    }*/
    
    /*void dfs_1(string &s, int st,vector<int> &sp, vector<string> &res,unordered_set<string> &dict){
        if (st>=s.size()){
            string str=s;
            for (int i=0;i<sp.size();i++){
                str.insert(sp[i]+i," ");
            }
            res.push_back(str);
        }else{
            for (unordered_set<string>::iterator it = dict.begin();it!=dict.end();it++){
                string  ss = *it;
                int sz = ss.size();
                if (s.compare(st,sz,ss)==0){
                    sp.push_back(st+sz);
                    dfs(s,st+sz,sp,res,dict);
                    sp.pop_back();
                }
            }
        }
    }*/

    void dfs(string &s, int st,vector<int> &sp, vector<string> &res,unordered_set<string> &dict, vector<vector<bool> > &mp){
        if (st>=s.size()){
            string str=s;
            for (int i=0;i<sp.size()-1;i++){
                str.insert(sp[i]+i," ");
            }
            res.push_back(str);
        }else{
            for (int j=0;j<mp[st].size();j++){
                if (mp[st][j]==true){
                    sp.push_back(j+1);
                    dfs(s,j+1,sp,res,dict,mp);
                    sp.pop_back();
                }
            }
        }
    }

    vector<string> wordBreak(string s, unordered_set<string> &dict) {
        vector<vector<bool> > mp(s.size(),vector<bool>(s.size(),false));
        for (int i=0;i<s.size();i++){
            for (int j=i;j<s.size();j++){
                if (dict.find(s.substr(i,j-i+1))!=dict.end()){
                    mp[i][j]=true;
                }
            }
        }
        bool flag =false;
        for (int i=0;i<s.size();i++){
            if (mp[i][s.size()-1]){
                flag = true; break;
            }
        }
        vector<string> res;
        vector<int>sp;
        if (!flag){return res;}
        dfs(s,0,sp,res,dict,mp);
        return res;
    }
};