Trailing Zeros

Trailing Zeros

Write an algorithm which computes the number of trailing zeros in n factorial.

Example

11! = 39916800, so the out should be 2

Challenge

O(log N) time

Solution: 只要找里面有多少个5, 乘出来就会有多少个0,因为2永远是够的

# of 5:n/5+n/25+n/(5^3)…..

public long trailingZeros(long n) {
    long base = 5;//important to use long type
    long count = 0;
    while (n >= base) {
        count += n / base;
        base *= 5;
    }
    return count;
}
FacebookTwitterGoogle+Share

Maximum Subarray I & II & III

Maximum Subarray I

Given an array of integers, find a contiguous subarray which has the largest sum.

Example

For example, given the array [−2,2,−3,4,−1,2,1,−5,3], the contiguous subarray [4,−1,2,1] has the largest sum = 6.

Note

The subarray should contain at least one number

Challenge

Can you do it in time complexity O(n)?

Solution: O(n) time O(1) space. one pass. Prefix Sum

 

public int maxSubArray(ArrayList<Integer> nums) {
    if (nums == null || nums.size() == 0) {
        return 0;
    }
    int maxSum = Integer.MIN_VALUE;
    int sum = 0;
    int minSum = 0;
    for (Integer num : nums) {
        sum += num;
        maxSum = Math.max(maxSum, sum - minSum);
        minSum = Math.min(minSum, sum);
    }
    return maxSum;
}

Minimum Subarray

Minimum Subarray

Given an array of integers, find the subarray with smallest sum.

Return the sum of the subarray.

Example

For [1, -1, -2, 1], return -3

Note

The subarray should contain at least one integer.

Solution: O(n) time O(1) space. one pass. Prefix Sum

 

public int minSubArray(ArrayList<Integer> nums) {
    if (nums == null || nums.size() == 0) {
        return 0;
    }
    int minSum = Integer.MAX_VALUE;
    int sum = 0;
    int maxSum = 0;
    for (Integer num : nums) {
        sum += num;
        minSum = Math.min(minSum, sum - maxSum);
        maxSum = Math.max(maxSum, sum);
    }
    return minSum;
}

Majority Number I & II & III

Majority Number I (找一个出现次数>1/2的数)

Given an array of integers, the majority number is the number that occurs more than half of the size of the array. Find it.

Example

Given [1, 1, 1, 1, 2, 2, 2], return 1

Challenge

O(n) time and O(1) extra space

Solution: 用的抵消的思想,如果两个数不一样大,就相互抵消,一样大就保留, 用count计数

public int majorityNumber(ArrayList<Integer> nums) {
    int candidate = -1;
    int count = 0;
    for (int i = 0; i < nums.size(); i++) {
        if (count == 0) {
            candidate = nums.get(i);
            count++;
        } else {
            if (candidate == nums.get(i)) {
                count++;
            } else {
                count--;
            }
        }
    }
    return candidate;
}

Majority Number II (找一个出现次数>1/3的数)

Given an array of integers, the majority number is the number that occurs more than 1/3 of the size of the array.

Find it.

Example

Given [1, 2, 1, 2, 1, 3, 3], return 1.

Note

There is only one majority number in the array.

Challenge

O(n) time and O(1) extra space.

Solution: 策略和I一样,只是现在有两个candidate,

public int majorityNumber(ArrayList<Integer> nums) {
    int candidate1 = -1;
    int candidate2 = -1;
    int count1 = 0;
    int count2 = 0;
    for (Integer num : nums) {
        if (candidate1 == num) {
            count1 ++;
        } else if (candidate2 == num) {
            count2 ++;
        } else if (count1 == 0) {
            candidate1 = num;
            count1 = 1;
        } else if (count2 == 0) {
            candidate2 = num;
            count2 = 1;
        } else {
            count1--;
            count2--;
        }
    }
    if (count1 == 0) {
        return candidate2;
    }
    if (count2 == 0) {
        return candidate1;
    }
    count1 = 0;
    count2 = 0;
    for (Integer num : nums) {
        if (num == candidate1) {
            count1++;
        }
        if (num == candidate2) {
            count2++;
        }
    }
    return count1 > count2 ? candidate1 : candidate2;
}

Majority Number III (找一个出现次数>1/k的数)

Given an array of integers and a number k, the majority number is the number that occurs more than 1/k of the size of the array.

Find it.

Example

Given [3,1,2,3,2,3,3,4,4,4] and k=3, return 3.

Note

There is only one majority number in the array.

Challenge

O(n) time and O(k) extra space

Solution: Similar approach as I & II

public int majorityNumber(ArrayList<Integer> nums, int k) {
    Map<Integer, Integer> majorityCounts = new HashMap<>();
    for (Integer num : nums) {
        if (majorityCounts.containsKey(num)) {
            majorityCounts.put(num, majorityCounts.get(num) + 1);
        } else {
            if (majorityCounts.size() < k - 1) {
                majorityCounts.put(num, 1);
            } else {
                List<Integer> toBeRemoved = new ArrayList<>();
                for (Integer key : majorityCounts.keySet()) {
                    if (majorityCounts.get(key) > 1) {
                        majorityCounts.put(key, majorityCounts.get(key) - 1);
                    } else {
                        toBeRemoved.add(key);
                    }
                }
                //important here: can not remove the element while iterating the set
                //which will cause ConcurrentModificationException
                for (Integer key : toBeRemoved) {
                    majorityCounts.remove(key);
                }
            }
        }
    }
    Set<Integer> results = majorityCounts.keySet();
    int maxCount = 0;
    int candidate = 0;
    for (Integer key : majorityCounts.keySet()) {
        majorityCounts.put(key, 0);
    }
    for (Integer num : nums) {
        if (majorityCounts.containsKey(num)) {
            int count = majorityCounts.get(num) + 1;
            majorityCounts.put(num, count);
            if (count > maxCount) {
                maxCount = count;
                candidate = num;
            }
        }
    }
    return candidate;
}

Max Tree

Max Tree

Given an integer array with no duplicates. A max tree building on this array is defined as follow:

  • The root is the maximum number in the array
  • The left subtree and right subtree are the max trees of the subarray divided by the root number.

Construct the max tree by the given array.

Example

Given [2, 5, 6, 0, 3, 1], the max tree constructed by this array is:

<code>    6
   / \
  5   3
 /   / \
2   0   1
</code>
Challenge

O(n) time and memory.

Solution: 用stack来维护在每个数出现前比它大得数。

策略:

When new node comes in, if it is larger than the peek, stack.pop() and at the same time append it as the new node’s left child. until the stack peek is larger than the new node or the stack is empty, at this time, the peek.right = new node. then we push new node into the stack. if the stack is empty when the new node is pushed, the new node is the temporary root.

用7,3,8,2,4,5走一遍就理解了

public TreeNode maxTree(int[] A) {
    if (A == null || A.length == 0) {
        return null;
    }
    Stack<TreeNode> stack = new Stack<>();
    TreeNode root = null;
    for (int i = 0; i < A.length; i++) {
        TreeNode curr = new TreeNode(A[i]);
        while (!stack.isEmpty() && A[i] >= stack.peek().val) {
            TreeNode tmp = stack.pop();
            tmp.right = curr.left;
            curr.left = tmp;
        }
        if (!stack.isEmpty()) {
            stack.peek().right = curr;
        } else {
            root = curr;
        }
        stack.push(curr);
    }
    return root;
}

Largest Rectangle in Histogram

Largest Rectangle in Histogram

Given n non-negative integers representing the histogram’s bar height where the width of each bar is 1, find the area of largest rectangle in the histogram.

histogram

Above is a histogram where width of each bar is 1, given height = [2,1,5,6,2,3].

histogram

The largest rectangle is shown in the shaded area, which has area = 10 unit.

Example

Given height = [2,1,5,6,2,3],
return 10.

Solution: max(the area of rectangle which height[i] is the shortest bar)

leftBound[i]: index of the first element less than height[i] starting from the left +1

rightBound[i]: index of the first element less than height[i] starting from the right -1

result = max(height[i]*(rightBound[i]-leftBound[i]))

注意:凡是求左边第一个比它小得数这类问题 用stack 存数组的index

策略是:

如果新来的数大于A[stack.peek()], 直接push i to stack, otherwise stack.pop()直到找到第一个比他小得数停下,push i to stack.

这样对一个array来说 只要走一遍就知道每一个数的左边第一个比它小的数是哪个。

O(n) time.

Solution 1. Straightforward Version

public int largestRectangleArea(int[] height) {
    if (height == null || height.length == 0) {
        return 0;
    }
    int[] leftBound = new int[height.length];
    int[] rightBound = new int[height.length];
    Stack<Integer> minStack = new Stack<>();
    for (int i = 0; i < height.length; i++) {
        while (!minStack.isEmpty() && height[i] <= height[minStack.peek()]) {
            minStack.pop();
        }
        if (minStack.isEmpty()) {
            leftBound[i] = 0;
        } else {
            leftBound[i] = minStack.peek() + 1;
        }
        minStack.push(i);
    }
    minStack = new Stack<>();
    for (int i = height.length - 1; i >= 0; i--) {
        while (!minStack.isEmpty() && height[i] <= height[minStack.peek()]) {
            minStack.pop();
        }
        if (minStack.isEmpty()) {
            rightBound[i] = height.length - 1;
        } else {
            rightBound[i] = minStack.peek() - 1;
        }
        minStack.push(i);
    }
    int maxArea = 0;
    for (int i = 0; i < height.length; i++) {
        int area = height[i] * (rightBound[i] - leftBound[i] + 1);
        maxArea = Math.max(maxArea, area);
    }
    return maxArea;
}

Solution 2. Fancy Version, One pass

public int largestRectangleArea(int[] height) {
    if (height == null || height.length == 0) {
        return 0;
    }
    Stack<Integer> minStack = new Stack<>();
    int maxArea = 0;
    for (int i = 0; i <= height.length; i++) {
        int curr = (i == height.length) ? -1 : height[i];
        while (!minStack.isEmpty() && curr <= height[minStack.peek()]) {
            int tmp = minStack.pop();
            int left = minStack.isEmpty() ? 0 : minStack.peek() + 1;
            int area = (i - left) * height[tmp];
            maxArea = Math.max(area, maxArea);
        }
        minStack.push(i);
    }
    return maxArea;
}

Lintcode: Data Stream Median

Data Stream Median

Numbers keep coming, return the median of numbers at every time a new number added.

 

Example

For numbers coming list: [1, 2, 3, 4, 5], return [1, 1, 2, 2, 3].

For numbers coming list: [4, 5, 1, 3, 2, 6, 0], return [4, 4, 4, 3, 3, 3, 3].

For numbers coming list: [2, 20, 100], return [2, 2, 20].

Challenge

Total run time in O(nlogn).

Clarification

What’s the definition of Median? – Median is the number that in the middle of a sorted array. If there are n numbers in a sorted array A, the median is A[(n - 1) / 2]. For example, if A=[1,2,3], median is 2. If A=[1,19], median is 1.

Solution: 维护两个堆 左边是max heap右边是min heap。当有新的数进来时先比较两个heap的数量 永远让left和right的size一样或者left比right多1, 这样的话median永远是left.poll()。然后确定好应该加到哪个heap之后,要比较当前数和两个堆顶数的大小,来决定是直接把该数放到那个heap中还是应该把另外一个heap的root放过来然后把这个数放到另外那个堆里。

O(NlogN) time.

public int[] medianII(int[] nums) {
	if (nums == null || nums.length == 0) {
		return nums;
	}
	int initialSize = 20;
	int[] median = new int[nums.length];
	Queue < Integer > leftHeap = new PriorityQueue < > (initialSize,
	new Comparator < Integer > () {
		public int compare(Integer a, Integer b) {
			return b - a;
		}
	});
	Queue < Integer > rightHeap = new PriorityQueue < > ();

	for (int i = 0; i < nums.length; i++) {
		if (leftHeap.size() > rightHeap.size()) {
			//need to put this one to rightHeap
			if (nums[i] >= leftHeap.peek()) {
				rightHeap.offer(nums[i]);
			} else {
				rightHeap.offer(leftHeap.poll());
				leftHeap.offer(nums[i]);
			}
		} else {
			//need to put this one to leftHeap
			if (leftHeap.isEmpty() && rightHeap.isEmpty()) {
				leftHeap.offer(nums[i]);
			} else {
				if (nums[i] <= rightHeap.peek()) {
					leftHeap.offer(nums[i]);
				} else {
					leftHeap.offer(rightHeap.poll());
					rightHeap.offer(nums[i]);
				}
			}
		}
		median[i] = leftHeap.peek();
	}
	return median;
}

LRU Cache

LRU Cache

Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get and set.

get(key) – Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
set(key, value) – Set or insert the value if the key is not already present. When the cache reached its capacity, it should invalidate the least recently used item before inserting a new item.

Solution: Use a doubly linked list, with a head and tail node pointers, as well as a hashMap with all the key and node pairs.

1. When get(), it first checks if the key is in the map, if it is, remove that node from its original position and move to the tail (right before the tail node). if it doesn’t exists, return -1.

2. When set(key, value), it first call get function, to see if it exists, them update the value, otherwise, check if the queue is full, then remove the first element (the one right after head node) and add the new node to the tail.

Set(), Get() O(1) Time.

public class Solution {
    public class Node {
        int key;
        int value;
        Node prev;
        Node next;
        public Node(int key, int value) {
            this.key = key;
            this.value = value;
            this.prev = null;
            this.next = null;
        }
    }

    Map<Integer, Node> cache;
    int capacity;
    Node head;
    Node tail;

    public Solution(int capacity) {
        cache = new HashMap<>();
        this.capacity = capacity;
        head = new Node(0, 0);
        tail = new Node(0, 0);
        head.next = tail;
        tail.prev = head;
    }

    public int get(int key) {
        if (cache.containsKey(key)) {
            //remove it from its original place
            //put to the tail the queue
            Node node = cache.get(key);
            removeNode(node);
            addToTail(node);
            return node.value;
        }
        return -1;
    }

    public void set(int key, int value) {
        if (get(key) != -1) {
            cache.get(key).value = value;
            return;
        }
        Node newNode = new Node(key, value);
        if (cache.size() < capacity) {
            addToTail(newNode);
        } else {
            cache.remove(head.next.key);
            removeNode(head.next);
            addToTail(newNode);
        }
        cache.put(newNode.key, newNode);
    }

    public void addToTail(Node node) {
        node.prev = tail.prev;
        node.prev.next = node;
        node.next = tail;
        tail.prev = node;
    }

    public void removeNode(Node node) {
        if (node.prev != null) {
            node.prev.next = node.next;
        }
        if (node.next != null) {
            node.next.prev = node.prev;
        }
        node.next = null;
        node.prev = null;
    }
}

 

Min Stack

Min Stack

Implement a stack with min() function, which will return the smallest number in the stack.

It should support push, pop and min operation all in O(1) cost.

Example

Operations: push(1), pop(), push(2), push(3), min(), push(1), min() Return: 1, 2, 1

Note

min operation will never be called if there is no number in the stack

Solution: 用一个minStack维护最小值,保存每一个状态的最小值。当新来的数比当前的栈顶小的时候,也就是说这个数是最小值,push to minStack,pop的时候要看pop的这个数是不是和minStack的栈顶一样,也就是这个数是最小数,stack.pop()的同时要minStack.pop(). 注意duplicates numbers, 所以push一个和当前最小数一样大的数时,也需要push to minStack.

这里的时间复杂度是平均时间复杂度。

public class Solution {
    Stack<Integer> minStack;
    Stack<Integer> stack;
    public Solution() {
        stack = new Stack<>();
        minStack = new Stack<>();
    }

    public void push(int number) {
        stack.push(number);
        if(minStack.isEmpty()){
            minStack.push(number);
        }else{
            if(minStack.peek()>=number){
                minStack.push(number);
            }
        }
    }

    public int pop() {
        if(stack.peek().equals(minStack.peek())){
            minStack.pop();
        }
        return stack.pop();
    }

    public int min() {
        return minStack.peek();
    }
}

Longest Consecutive Sequence

Longest Consecutive Sequence

Given an unsorted array of integers, find the length of the longest consecutive elements sequence.

Example

Given [100, 4, 200, 1, 3, 2],
The longest consecutive elements sequence is [1, 2, 3, 4]. Return its length: 4.

Clarification

Your algorithm should run in O(n) complexity.

Solution: 建一个hash表 对每一个num[i]上下浮动寻找num[i]+1, num[i]+2, …, 和num[i]-1, num[i]-2, …是不是在表里 如果找到的话就把该数从hash表里删除避免重复查找,所以建表时间是O(n) 每个数只会被访问一次,所以时间复杂度是O(n).

public int longestConsecutive(int[] num) {
    Set<Integer> numSet = new HashSet<>();
    for (int i = 0; i < num.length; i++) {
        numSet.add(num[i]);
    }
    int maxLength = 0;
    for (int i = 0; i < num.length; i++) {
        if (numSet.contains(num[i])) {
            int length = 1;
            int curr = num[i] - 1 ;
            while (numSet.contains(curr)) {
                numSet.remove(curr);
                length++;
                curr--;
            }
            curr = num[i] + 1;
            while (numSet.contains(curr)) {
                numSet.remove(curr);
                length++;
                curr++;
            }
            if (length > maxLength) {
                maxLength = length;
            }
        }
    }
    return maxLength;
}