Interview Preparation Notes PDF
Interview Preparation Notes PDF
of Contents
Introduction 1.1
Algorithm 1.2
Array 1.2.1
Partition Array 1.2.1.1
Small Difference 1.2.1.2
Sub-array Sum I 1.2.1.3
Sub-array Sum II 1.2.1.4
Longest Common Sub-sequence 1.2.1.5
Longest Increasing Continuous I Sub-sequence 1.2.1.6
Longest Increasing Continuous Sub-sequence II 1.2.1.7
Matrix 1.2.2
Max Points on A line 1.2.2.1
Search In Matrix I 1.2.2.2
Search In Matrix II 1.2.2.3
Set Zero 1.2.2.4
Rotate Matrix 1.2.2.5
Sub-matrix Sum 1.2.2.6
String 1.2.3
Longest Sub-string has K Distinct Character 1.2.3.1
Longest Sub-string Windows has Non-repeat Characters 1.2.3.2
Minimum Window 1.2.3.3
Word Pattern 1.2.3.4
Longest Palindromic Substring 1.2.3.5
Shortest Word Distance 1.2.3.6
Group Shifted String 1.2.3.7
Encode String 1.2.3.8
Encode and Decode Strings 1.2.3.9
1
Palindrome Permutation 1.2.3.10
Sort 1.2.4
Elementary Sort 1.2.4.1
Advanced Sort 1.2.4.2
Linear Sort 1.2.4.3
Sort Color I 1.2.4.4
Sort Color II 1.2.4.5
Largest Number 1.2.4.6
Wiggle Sort 1.2.4.7
Sort Letters by Case 1.2.4.8
Binary Search 1.2.5
Closest Number 1.2.5.1
3 Sum Smaller 1.2.5.2
Count Smaller Number 1.2.5.3
Triangle Count 1.2.5.4
Recursion 1.2.6
Print Numbers by Recursion 1.2.6.1
Permutation 1.2.7
Permutation Index I 1.2.7.1
Permutation Index II 1.2.7.2
Permutation Sequence 1.2.7.3
Next Permutation 1.2.7.4
Previous Permutation 1.2.7.5
Backtracking 1.2.8
K Sum II 1.2.8.1
N Queen I 1.2.8.2
N Queen II 1.2.8.3
Subsets 1.2.8.4
Phone Number 1.2.8.5
Boggle Game 1.2.8.6
2
Scramble Number Pair Calculator 1.2.8.7
Strobogrammatic Number 1.2.8.8
Factor Combinations 1.2.8.9
Dynamic Programming 1.2.9
Home Robber 1.2.9.1
Backpack I 1.2.9.2
Backpack II 1.2.9.3
Edit Distance 1.2.9.4
Longest Increasing Subsequence 1.2.9.5
Minimum Adjustment Cost 1.2.9.6
Coins in A Line (I ~ III) 1.2.9.7
Distinct Subsequences 1.2.9.8
Maximal Square 1.2.9.9
Interleaving String 1.2.9.10
Word Break 1.2.9.11
Scramble String 1.2.9.12
Maximum Subarray III 1.2.9.13
Paint House 1.2.9.14
Linked List 1.2.10
Remove Linked List Element 1.2.10.1
Remove Nth Element from End of List 1.2.10.2
Swap Nodes by Pairs in Linked List 1.2.10.3
Intersection of Linked List 1.2.10.4
Flatten Binary Tree to Linked List 1.2.10.5
Palindrome Linked List 1.2.10.6
Reverse List in K-Group 1.2.10.7
Copy Random Pointer 1.2.10.8
Merge K Sorted Linked List 1.2.10.9
Convert Linked List to Binary Search Tree 1.2.10.10
Tree 1.2.11
3
Tree Traversal 1.2.11.1
Invert Tree 1.2.11.2
Depth of Tree 1.2.11.3
Balanced Tree 1.2.11.4
Lowest Common Ancestor 1.2.11.5
Search Range in Binary Search Tree 1.2.11.6
Count Univalue Subtree 1.2.11.7
Verify Preorder Sequence in BST 1.2.11.8
Closest BST Value 1.2.11.9
Graph 1.2.12
Route Between Directed Graph 1.2.12.1
Graph Valid Tree 1.2.12.2
Find the Celebrity 1.2.12.3
Alien Dictionary 1.2.12.4
Segment Tree 1.2.13
Segment Tree Build I 1.2.13.1
Segment Tree Build II 1.2.13.2
Segment Tree Query I 1.2.13.3
Segment Tree Query II 1.2.13.4
Segment Tree Modify 1.2.13.5
Interval Sum I 1.2.13.6
Interval Sum II 1.2.13.7
Interval Minimum Number 1.2.13.8
Count Smaller Number before itself 1.2.13.9
Math 1.2.14
Integer To Roman 1.2.14.1
Roman to Integer 1.2.14.2
Ugly Number I 1.2.14.3
Ugly Number II 1.2.14.4
Fast Power 1.2.14.5
4
Square Root 1.2.14.6
Binary Representation 1.2.14.7
Divide Two Integers 1.2.14.8
Digit Counts 1.2.14.9
Expression 1.2.15
Reverse Polish Notation (RPN) 1.2.15.1
Convert Expression to RPN 1.2.15.2
Convert Expression to PN 1.2.15.3
Calculator 1.2.15.4
Expression Tree Build 1.2.15.5
Bit Manipulation 1.2.16
Update Bits 1.2.16.1
Data Structure 1.3
Primitive Type 1.3.1
Collection 1.3.2
Array List 1.3.2.1
Linked List 1.3.2.2
Stack 1.3.2.3
Queue 1.3.2.4
Hash Set 1.3.2.5
Map 1.3.3
Hash Map 1.3.3.1
Iterator 1.3.4
Iterator for Two Dimension Array 1.3.4.1
Iterator of Iterators 1.3.4.2
Peek Iterator 1.3.4.3
Even Iterator 1.3.4.4
Jump Iterator 1.3.4.5
Joint Set 1.3.5
Prefix Tree 1.3.6
5
Trie Tree 1.3.6.1
Segment Tree 1.3.7
Object Oriented Programming 1.4
Design Pattern 1.4.1
Practice 1.4.2
Deck Card 1.4.2.1
Chess Game 1.4.2.2
Online Reader 1.4.2.3
Parking Lot 1.4.2.4
Vending Machine 1.4.2.5
System Design 1.5
Distributed System Knowledge 1.5.1
Behavior Questions 1.6
Questions on Past Projects 1.6.1
6
Introduction
Introduction
Notebook for Interview Question Preparation includes Algorithm, Data Structure,
Object-Oriented Programming and System Design. Everything for Technical
Interview. Most of Questions come from Leetcode / Lintcode / Cracking Coding
Interview / Nine Chapter Online Course / GeeksForGeeks / HackerRank.
Algorithm Part:
1. Categories of algorithm questions
Pointer
Sort and Search
From recursion to Dynamic Programming
Mathematics in CS
Big Data
2. The analysis and summary of programming problems, and most of the
programming problems come from Leetcode, Lintcode and GeeksForGeeks.
7
Introduction
8
Algorithm
Algorithm
Algorithm is most interesting part in computer science. It measure a person how
smart and how deep in learning computer science.
I concluded some parts or categories of algorithm questions, but all of these are
intertwined together. In one algorithm question, it can combine multiple knowledge
points with several categories.
As I know, the algorithm should contains two things. The data, which is the source
of information, is the stuff what the algorithm manipulates; Another is strategy, the
core of algorithm, which is the thinking, the soul. Here I mainly focus on concludes
the strategy that commonly used in algorithm interview questions.
1. Pointers
Base on Purpose
9
Algorithm
Remove Duplicate
Make Partition
Do swap
Find element
Sort
Selection Sort
Insertion Sort
Bubble Sort
Merge Sort
Quick Sort
Count Sort
Radix Sort
Search
Binary Search
Ternary Search
Breath First Search
Depth First Search
Union Find
Recursion
10
Algorithm
Backtracking
Combination
Permutation
N Queen
Dynamic Programming
Matrix DP
One Sequence DP
Two Sequence DP
Backpack
Math
Greatest Common Division
Least Common Multiple
Elementary Arithmetic Operation with Bitwise Idea
Binary, octonary and tenary
Power and square root (Divide and Conquer)
Bitwise Manipulation
OR's Magic
Left or Right Shifting
5. Big Data
Top K Problem
Kth largest / smallest element in dataset
Find median in data stream
Top K frequent element
11
Algorithm
Cache Algorithm
Least Recently Used
Least Frequently Used
Bit Set
External Sort
Bloom Fliter
12
Array
Array
Array is most fundamental container to hold multiple elements. It the skeletal part
of Array List. In java, array can contain both primitive element or object.
Attribute
Index
Value
Routines
The array can be applied to every algorithm. Th Basic question for testing typically
array knowledge are following:
13
Partition Array
Given an array nums of integers and an int k , partition the array (i.e move the
elements in "nums") such that:
Return the partitioning index, i.e the first index i nums[i] >= k.
Solution:
Typical index rotate two pointer problem, looks like the idea of quick sort .
Set an index pivot for marking the real position of element less than k
during pass the orginal array.
Once the current passing index i hits the element less than k , we do the
swap with pivot and i .
Make sure the pivot should add 1 after swap since the marked position is
increase for next one.
However in new pivot position we not sure the element's value, so... we
need to check in next procedure.
Make sure the i position decrease 1, because we just did a swap and we
need to check the new i is less than 'k'
14
Partition Array
int pivot = 0;
for(int i = 0; i < nums.length; i++) {
if(i > pivot && nums[i] < k) {
int tmp = nums[pivot];
nums[pivot++] = nums[i];
nums[i--] = tmp;
}
}
// this is just for corner case when the last element st
ill less than k
if(nums[nums.length - 1] < k)
return nums.length;
return pivot;
}
}
15
Small Difference
Given two array of integers(the first array is array A, the second array is array B),
now we are going to find a element in array A which is A[i], and another element in
array B which is B[j], so that the difference between A[i] and B[j] (|A[i] - B[j]|) is as
small as possible, return their smallest difference.
Example
For example, given array A = [3,6,7,4] , B = [2,8,9,3] , return 0
Challenge
O(n log n) time
Solution
Do sort on one of array
One pass on another array and do binary search on the sorted array.
Search the target value from passing array and get the minimum difference
on sorted array
Update the global minimum difference each time.
16
Small Difference
17
Sub-array Sum I
Given an integer array, find a subarray where the sum of numbers is zero. Your
code should return the index of the first number and the index of the last number.
Solution
18
Sub-array Sum II
Given an integer array, find a subarray where the sum of numbers is between two
given interval. Your code should return the number of possible answer.
Example
Given [1,2,3,4] and interval = [1,3] , return 4 . The possible answers are:
[0, 0]
[0, 1]
[1, 1]
[2, 2]
Solution
19
Sub-array Sum II
Arrays.sort(A);
for(int i = 0; i < A.length; i++) {
if(A[i] >= start && A[i] <= end)
res++;
// start <= A[i] - A[j] <= end
// so the max bound and min bound of A[j] are follow
ing:
int max = A[i] - start;
int min = A[i] - end;
// max + 1 make sure the right bound of max value an
d also index problem
int range = findInsPos(A, max + 1) - findInsPos(A, m
in);
res += range;
}
return res;
}
private int findInsPos(int[] A, int value) {
int l = 0, r = A.length - 1;
while(l < r - 1) {
int m = l + ((r - l) >>1);
if(A[m] < value)
l = m;
else
r = m;
}
if(A[l] >= value)
return l;
else
return r;
}
20
Sub-array Sum II
21
Longest Common Sub-sequence
Example
For ABCD and EDCA , the LCS is A (or D , C ), return 1.
Solution
22
Longest Common Sub-sequence
23
Longest Increasing Continuous I Sub-sequence
Give you an integer array (index from 0 to n-1, where n is the size of this array),
find the longest increasing continuous subsequence in this array. (The definition of
the longest increasing continuous subsequence here can be from right to left or
from left to right)
Example
For [5, 4, 2, 1, 3] , the LICS is [5, 4, 2, 1] , return 4 .
Note
O(n) time and O(1) extra space.
Solution
This is O(1) space dynamic programming. Just maintain one local max and
one global max variable.
The default value of local maximum variable is 2.
The condition for growing the local maximum is by (A[i] - A[i-1])*(A[i-
1] - A[i-2]) > 0 , which means [i-2] < [i-1] < [i] or [i-2] >
[i-1] > [i] .
24
Longest Increasing Continuous I Sub-sequence
int max = 2;
int cur = 2;
for(int i = 2; i < A.length; i++) {
if((A[i] - A[i-1])*(A[i-1] - A[i-2]) > 0){
cur ++;
}else
cur = 2;
max = Math.max(max, cur);
}
return max;
}
}
25
Longest Increasing Continuous Sub-sequence II
Give you an integer matrix (with row size n, column size m),find the longest
increasing continuous subsequence in this matrix. (The definition of the longest
increasing continuous subsequence here can start at any row or column and go
up/down/right/left any direction).
Example
Given a matrix:
[
[1 ,2 ,3 ,4 ,5],
[16,17,24,23,6],
[15,18,25,22,7],
[14,19,20,21,8],
[13,12,11,10,9]
]
return 25
Challenge
O(nm) time and memory.
Solution:
This is great question with DFS, Dynamic Problem and Subsequence idea.
The idea is also simple. Recursively search by DFS while we can do some
memorized stuff.
Each time we figure out the maximum length with reversed increasing
sequence from each element in matrix.
Note that the searching is by decreasing way.
26
Longest Increasing Continuous Sub-sequence II
*/
// memorized the local maximum length
int[][] memo;
boolean[] visited;
int n ,m;
int res = 0;
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++) {
memo[i][j] = helper(i, j, A);
res = Math.max(res, memo[i][j]);
}
}
return res;
}
if(visited[x * m + y])
return memo[x][y];
int res = 1;
for(int i = 0; i < 4; i++) {
int nx = x + dx[i];
27
Longest Increasing Continuous Sub-sequence II
int ny = y + dy[i];
if(0<= nx && nx < n && 0<= ny && ny < m ) {
// this is tricky point, we search by decreasing
if( A[x][y] > A[nx][ny])
res = Math.max(res, helper(nx, ny, A) + 1);
}
}
visited[x * m + y] = true;
memo[x][y] = res;
return res;
}
}
28
Matrix
29
Max Points on A line
Given n points on a 2D plane, find the maximum number of points that lie on the
same straight line.
Example
Given 4 points: (1,2) , (3,6) , (0,0) , (1,3) .
Solution
Use one point as a baseline. ( Point pa )
Iterate other points ( Point pb ) (index greater than pa ): j = i + 1 and
Use Hash Map to record the ratio and count
Note:
Ratio is double radio = (double)(pa.y - pb.y) / (double)(pa.x
- pb.x) ;
When pa.x == pb.x && pa.y == pb.y, consider two points are the same,
also need to count the same point.
When only pa.x == pb.x , that means the ratio is infinity as
(double)Integer.MAX_VALUE ;
When only pa.y == pb.y , that means the ratio is zero;
Iterate Hash Map and get the local max with updating the global max;
int maxLine = 0;
for(int i = 0; i < points.length; i++) {
Map<Double, Integer> map = new HashMap<>();
30
Max Points on A line
Point pa = points[i];
int same = 0;
for(int j = i + 1; j < points.length; j++) {
Point pb = points[j];
int cnt = 0;
if(pa.x == pb.x && pa.y == pb.y)
same ++;
else if(pa.x == pb.x) {
map.put((double)Integer.MAX_VALUE, map.c
ontainsKey((double)Integer.MAX_VALUE)?map.get((double)Integer.MA
X_VALUE) + 1 : 2);
}else if(pa.y == pb.y)
map.put((double)0, map.containsKey((doub
le)0)?map.get((double)0) + 1 : 2);
else{
double radio = (double)(pa.y - pb.y) / (
double)(pa.x - pb.x);
map.put(radio, map.containsKey(radio)?ma
p.get(radio) + 1 : 2);
}
}
int localMax = 1;
for (Integer value : map.values())
localMax = Math.max(localMax, value);
localMax += same;
maxLine = Math.max(maxLine, localMax);
}
return maxLine;
}
}
31
Search In Matrix I
Solution:
First binary search with checking the first element in each row so that we can
find the row may contain the target number;
So we search the lowbound of target number. However, we also can do if the
element is just equals to target number then directly return for reducing time.
Once we get the target row, then we do the second binary search in this row
to find the target number.
All in all, two binary search to find the target!
32
Search In Matrix I
}
int curRow;
if(matrix[up][0] > target)
return false;
else if(matrix[up][0] <= target && matrix[down][0] > tar
get)
curRow = up;
else
curRow = down;
int l = 0, r = matrix[curRow].length - 1;
while(l < r - 1) {
int m = l + ((r - l) >> 1);
if(matrix[curRow][m] == target)
return true;
else if(matrix[curRow][m] < target)
l = m;
else
r = m;
}
33
Search In Matrix II
Write an efficient algorithm that searches for a value in an m x n matrix, return the
occurrence of it.
Solution:
Typical Matrix Search Problem, using a condition for driven coordinate
moving.
Here the value and target comparasion is the driven condition.
Since the sorted matrix, we can start from right top element.
Because on the diagonal from right top to left down, all the left elements are
less than the right elments.
So we have three type of running condition and set the x, y coordinate
differently.
34
Search In Matrix II
35
Set Zero
Solution:
Use the first row (up row) and the first col (left col) to record the position info
of zeroes in matrix;
But we also need to set two boolean value to check if there is zero in first row
and first col;
Then go through the matrix again, when [i][0] is marked zero or [0][j] is
marked zero set current position as zero! This is important!;
Finally, go back to check two boolean value, and set that row or col as zero if
boolean value is true;
36
Set Zero
matrix[0][j] = 0;
}
if(row)
for(int j = 0; j < matrix[0].length; j++)
matrix[0][j] = 0;
if(col)
for(int i = 0; i < matrix.length; i++)
matrix[i][0] = 0;
}
}
37
Rotate Matrix
Solution:
Headache Implement question!
Very carefully to treat index.
Only calculate the 1/4 of index in matrix!
int n = matrix.length;
38
Sub-matrix Sum
Given an integer matrix, find a submatrix where the sum of numbers is zero. Your
code should return the coordinate of the left-up and right-down number.
Example
Given matrix
[
[1 ,5 ,7],
[3 ,7 ,-8],
[4 ,-8 ,9],
]
Challenge
O(n3) time.
39
String
String
Routines
Two Pointers
String Compress
String Serialization
40
Longest Sub-string has K Distinct Character
Given a string s, find the length of the longest substring T that contains at most k
distinct characters.
Example
For example, Given s = eceba , k = 3,
Challenge
O(n), n is the size of the string s.
Solution:
Set two pointers as a windows for input string.
Use a hashmap to store the characters in a window (substring) in string.
However, we notice that we use hashmap for count the character appearance
times.
Remove the character as a key only if the count for this key is zero.
Update the max window size each time.
41
Longest Sub-string has K Distinct Character
int prev = 0;
int maxLen = 0;
for(int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if(dict.containsKey(c)) {
dict.put(c, dict.get(c) + 1);
}else {
dict.put(c, 1);
while(dict.size() > k) {
char prevChar = s.charAt(prev++);
if(dict.get(prevChar) > 1)
dict.put(prevChar, dict.get(prevChar) -
1);
else
dict.remove(prevChar);
}
}
maxLen = Math.max(maxLen, i - prev + 1);
}
return maxLen;
}
}
42
Longest Sub-string has K Distinct Character
At the first I made a mistake by using hashset. However, like the previous
mentioned, we need to count the character appearance. Why? Since there is
possible when the character on index prev has another one in this window. But
when you simply remove this element, there is still one inside this window. Tha
makes the mistake happened!
int maxLen = 0;
int prev = 0;
for(int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
disc.add(c);
while(disc.size() > k){
disc.remove(s.charAt(prev++));
}
maxLen = Math.max(maxLen, i - prev + 1);
}
return maxLen;
}
43
Longest Sub-string Windows has Non-repeat Characters
Given a string, find the length of the longest substring without repeating
characters.
Example
For example, the longest substring without repeating letters for abcabcbb is
abc , which the length is 3.
Challenge
O(n) time
Solution:
Set two pointers as a windows for input string.
Very simple idea, to use a hashset to store the characters in a window
(substring) in string.
While the repeat detect, move forward the previous pointer.
Update the max window size each time.
44
Longest Sub-string Windows has Non-repeat Characters
int maxLen = 0;
int prev = 0;
for(int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
while(disc.contains(c)){
disc.remove(s.charAt(prev++));
}
maxLen = Math.max(maxLen, i - prev + 1);
disc.add(c);
}
return maxLen;
}
}
45
Minimum Window
Given a string source and a string target, find the minimum window in source
which will contain all the characters in target.
Example
source = "ADOBECODEBANC" target = "ABC" Minimum window is "BANC".
Note
If there is no such window in source that covers all characters in target, return the
emtpy string "".
If there are multiple such windows, you are guaranteed that there will always be
only one unique minimum window in source.
Challenge
Can you do it in time complexity O(n) ?
Clarification
The characters in minimum window doesn't need to has the same order in target.
Solution:
46
Minimum Window
);
47
Minimum Window
48
Word Pattern
Word Pattern
Given a pattern and a string str, find if str follows the same pattern.
Here follow means a full match, such that there is a bijection between a letter in
pattern and a non-empty word in str.
Examples:
pattern = abba , str = dog cat cat dog should return true. pattern = abba ,
str = dog cat cat fish should return false. pattern = aaaa , str = dog cat
cat dog should return false. pattern = abba , str = dog dog dog dog should
return false.
Notes:
You may assume pattern contains only lowercase letters, and str contains
lowercase letters separated by a single space.
Think
Firstly, you need to convert str into string array with spliting by space.
Check two stuffs are equal length, if not? directly return false!
Setup a hashmap for storing element both pattern and strs. However, the key
are different types: character, string. Why we do not just use string? Consider
about this case: pattern - abba , str - a a b a . Pattern and Word has the
same kind of element. It cannot easily to distinguish.
The value in hashmap should be the
There is one more tricky thing: why we compare the map.put() return
value? Here is a segment in HashMap API.
49
Word Pattern
Solution
Problem II
Given a pattern and a string str , find if str follows the same pattern.
Here follow means a full match, such that there is a bijection between a letter in
pattern and a non-empty substring in str .
50
Word Pattern
Examples
pattern = "abab" , str = "redblueredblue" should return true .
Notes
You may assume both pattern and str contains only lowercase letters.
Think
Got all combinations and check any combination matched the pattern
Solution
51
Word Pattern
52
Longest Palindromic Substring
Example
Given the string = "abcdzdcab" , return "cdzdc" .
Challenge
O(n2) time is acceptable. Can you do it in O(n) time.
Think
One pass on each position in string characters, assume the axis of symmetry
on each character or between two character:
| |
c a b a c f or c a b a c f
On each axis of symmetry we get the left and right pointers and make them
move toward left or right
left right
\ /
c a b a c f
...or...
l r
| |
c a b a c f
53
Longest Palindromic Substring
Solution
Analysis
54
Longest Palindromic Substring
One pass from 0 - ; inside the loop the palindromic substring search also costs
a loop from l - r; So the total is O( );
55
Shortest Word Distance
Problem I
Given a list of words and two words word1 and word2, return the shortest distance
between these two words in the list.
Example
Assume that words = ["practice", "makes", "perfect", "coding",
"makes"] . Given word1 = “coding” , word2 = “practice” , return 3 .
Given word1 = "makes" , word2 = "coding" , return 1 .
Note
You may assume that word1 does not equal to word2, and word1 and word2 are
both in the list.
Think
The problem can be solved by one-pass of the array.
Iterate through the array, use two pointers pointing to the index of the word1
and word2, maintain the minimum distance.
Solution
56
Shortest Word Distance
Problem II
This is a follow up of Problem I.The only difference is now you are given the list of
words and your method will be called repeatedly many times with different
parameters. How would you optimize it? Design a class which receives a list of
words in the constructor, and implements a method that takes two words word1
and word2 and return the shortest distance between these two words in the list.
Example,
Assume that words = ["practice", "makes", "perfect", "coding",
"makes"] . Given word1 = "coding" , word2 = "practice" , return 3 .
Given word1 = "makes" , word2 = "coding" , return 1 .
Think
Since the calls are from different words, we have to save the index for each
57
Shortest Word Distance
Solution
Problem III
58
Shortest Word Distance
This is a follow up of Problem I. The only difference is now word1 could be the
same as word2. Given a list of words and two words word1 and word2, return the
shortest distance between these two words in the list. word1 and word2 may be
the same and they represent two individual words in the list.
Example,
Assume that words = ["practice", "makes", "perfect", "coding",
"makes"] . Given word1 = "makes" , word2 = "coding" , return 1 . Given
word1 = "makes" , word2 = "makes" , return 3 .
Think
Most code should remain the same as the Problem I. But need to deal with
the situation that word1 and word2 are the same.
w1Idx always record the index when word[i].equals(word1) but
w2Idx should be assigned as the value from w1Idx when word1 ==
word2
Solution
59
Shortest Word Distance
60
Group Shifted String
"abc" -> "bcd" -> ... -> "xyz" Given a list of strings which contains only lowercase
alphabets, group all strings that belong to the same shifting sequence.
Example,
given: ["abc", "bcd", "acef", "xyz", "az", "ba", "a", "z"], Return:
[
["abc","bcd","xyz"],
["az","ba"],
["acef"],
["a","z"]
]
Note
For the return value, each inner list’s elements must follow the lexicographic order.
Think
There is a regular pattern: if two words are shifted, the distance between two
adjacent characters are the same.
2 3 2 3
/\ /\ /\ /\
a c f - > e g j
61
Group Shifted String
Solution
62
Group Shifted String
63
Encode String
Encode String
Given a String like "ABBCCCC" , encode it to A2B4C . Avoid to make the encode
string larger than original string. Do it in-place! The repeat count should less than
10.
Think
Pass the char array by reversed order so that it's easier to modify the char to
count number in-place
Index passing should from len - 2 to -1 , this is tricky part to avoid the
case when index is zero cannot be count
The in-place modification index come from the len - 1 , rewrite the result
char by this index
For the integer convert to character, it may need to use
Character.forDigit(count, 10)
For those rest char less than rewrite index, set them as null character
"\u0000"
Solution
64
Encode String
class Solution {
public static void main(String[] args) {
String str = "ABC";
inplaceEncode(str.toCharArray());
}
65
Encode and Decode Strings
So Machine 1 does:
Note
The string may contain any possible characters out of 256 valid ascii characters.
Your algorithm should be generalized enough to work on any possible characters.
66
Encode and Decode Strings
Do not use class member / global / static variables to store states. Your encode
and decode algorithms should be stateless.
Do not rely on any library method such as eval or serialize methods. You should
implement your own encode/decode algorithm.
Think
In theoretic way, there should be nothing can do separation for Strings
So just make the encode as adding the length of word and "#" before the
word
Decode function should be carefully designed
Solution
67
Encode and Decode Strings
return sb.toString();
}
68
Palindrome Permutation
Palindrome Permutation
Problem I
Given a string, determine if a permutation of the string could form a palindrome.
Example
"code" -> false , "aab" -> true , "carerac" -> true .
Think
The problem can be easily solved by count the frequency of each character using
a hash map. The only thing need to take special care is consider the length of the
string to be even or odd.
If the length is even. Each character should appear exactly times of 2, e.g. 2,
4, 6, etc..
If the length is odd. One and only one character could appear odd times.
Solution
69
Palindrome Permutation
int tolerent = 0;
for (Map.Entry<Character, Integer> entry : map.entrySet(
)) {
if (entry.getValue() % 2 != 0) {
tolerent++;
}
}
if (s.length() % 2 != 0)
return tolerent == 1;
else
return tolerent == 0;
}
Problem II
Given a string s, return all the palindromic permutations (without duplicates) of it.
Return an empty list if no palindromic permutation could be form.
Example
Given s = "aabb" , return ["abba", "baab"] . Given s = "abc" , return
[] .
Think
Similar with the last problem, check if the input String can form any valid
palindrome
Address the case when the length is odd
Record the character with odd frequency
70
Palindrome Permutation
Solution
71
Palindrome Permutation
72
Sort
Sort
Sorting is ordering a list of objects. We can distinguish two types of sorting. If the
number of objects is small enough to fits into the main memory, sorting is called
internal sorting. If the number of objects is so large that some of them reside on
external storage during the sort, it is called external sorting. In this chapter we
consider the following internal sorting algorithms
By Complexity
Time Complexity:
Bubble Sort
Selection Sort
Insertion Sort (min:
Time Complexity:
Quick Sort (Space Complexity: )
Merge Sort (Space Complexity: )
Heap Sort
Time Complexity: && Space Complexity:
Bucket sort
By Stable
Stable
Insertion sort
Merge Sort
Not Stable
Bubble Sort
Selection Sort
Quick Sort
Merge Sort
Heap Sort
73
Sort
74
Elementary Sort
Elementary Sort
These are most basic sort methods with time complexity.
Bubble Sort
Think
Swap when the two adjacent elements is not in order
Do a while loop until swap not happened in previous element order check
Solution
Insertion Sort
Think
Get the target value from head of array
75
Elementary Sort
Solution
Selection Sort
Think
Get the target value from head of array
Find the minimum element on the right of target, swap them if minimum less
then target
Solution
76
Elementary Sort
77
Advanced Sort
Advanced Sort
Merge Sort
Think
Divide and Conquer
Recursion
Solution
78
Advanced Sort
private void merge(int[] arr, int left, int mid, int right){
int[] newarr = new int[right - left + 1];
int l = 0;
int r = mid - left + 1;
for(int i = left; i <= right; i++){
if(l > mid - left)
arr[i] = newarr[r++];
else if(r > right - left)
arr[i] = newarr[l++];
else
arr[i] = newarr[l] < newarr[r]? newarr[l++] : newarr
[r++];
}
}
Quick Sort
Think
Set pivot (the rear of array or ) and consider it as a standard
Pass the array and make the element less than pivot on the pivot's left and
the element larger than pivot on the pivot's right;
Solution
79
Advanced Sort
80
Linear Sort
Linear Sort
There are sorting algorithms that run faster than time but they require
special assumptions about the input sequence to be sort. Examples of sorting
algorithms that run in linear time , are counting sort, radix sort and bucket
sort. Counting sort and radix sort assume that the input consists of integers in a
small range. Whereas, bucket sort assumes that the input is generated by a
random process that distributes elements uniformly over the interval.
Bucket Sort
Think
Setup n buckets ( n is the range of elements value)
Put elements in each bucket
Space consuming
Solution
81
Linear Sort
Radix Sort
Think
Solution
82
Sort Color I
Sort Color
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.
Example
Given [1, 0, 1, 2], return [0, 1, 1, 2].
Note
You are not suppose to use the library's sort function for this problem.
Challenge
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?
Think
Index mark O's first position from head and 2's first position from the rear.
Exchange the two values.
Solution
83
Sort Color I
84
Sort Color II
Sort Color II
Given an array of n objects with k different colors (numbered from 1 to k), sort
them so that objects of the same color are adjacent, with the colors in the order 1,
2, ... k.
Example
Given colors=[3, 2, 2, 1, 4], k=4, your code should sort colors in-place to [1, 2, 2,
3, 4].
Note
You are not suppose to use the library's sort function for this problem.
Challenge
A rather straight forward solution is a two-pass algorithm using counting sort. That
will cost O(k) extra memory. Can you do it without using extra memory?
Think #1
Bucket Sort but space complexity with
Solution #1
85
Sort Color II
/**
* @param colors: A list of integer
* @param k: An integer
*/
public void sortColors2(int[] colors, int k) {
if(colors == null || colors.length == 0)
return;
Think #2
Complex bucket sort with in-place counting
Get a value and find its index by value - 1
If the target index has another value, exchange and set target index as -1
If target index is counter, make it minus 1, e.g. -2 and set original index as
0
Steps like following:
86
Sort Color II
3 2 2 1 4
2 2 -1 1 4
2 -1 -1 1 4
0 -2 -1 1 4
-1 -2 -1 0 4
-1 -2 -1 -1 0
Solution #2
87
Sort Color II
/**
* @param colors: A list of integer
* @param k: An integer
* @return: nothing
*/
public void sortColors2(int[] colors, int k) {
if(colors == null || colors.length == 0)
return;
88
Largest Number
Largest Number
Given a list of non negative integers, arrange them such that they form the largest
number.
For example, given [3, 30, 34, 5, 9] , the largest formed number is
9534330 .
Note
The result may be very large, so you need to return a string instead of an integer.
Think
Sort the elements in array by the rule of pair combination:
a, b -> compare(ab, ba) ;
One pass the sorted array and make the largest number
Solution
89
Largest Number
Arrays.sort(Snum,comp);
if(Snum[Snum.length-1].charAt(0)=='0')
return "0";
for(String s: Snum)
sb.insert(0, s);
return sb.toString();
}
90
Wiggle Sort
Wiggle Sort
Given an array, and re-arrange it to wiggle style in one pass.
Example
[1] A0 >= A1 <= A2 >= A3 .... .... An
Think
Base case. The first two elements , satisfy the rules, and is in its desired
position.
Suppose , .... satisfy the rules, and , .... are in their desired positions.
We want to show that when we consider the pair and , the rules are not
violated, and the new k-th element will be in its desired position. Without loss of
generality, assume that the k-th element should be higher than both of its
neighbors. Two cases:
1) > . We are good in this case. is its desired position, and no rules are
violated so far.
2) < . We swap and . Note that this does not violate , since
< < . And the new k-th element (previous ) satisfies the rules, and
is in its desired position.
So throughout the process, we do not violate any rules. The algorithm is correct.
Solution
91
Wiggle Sort
92
Sort Letters by Case
Example
For "abAcD", a reasonable answer is "acbAD"
Note
It's not necessary to keep the original order of lower-case letters and upper case
letters.
Challenge
Do it in one-pass and in-place.
Solution
93
Sort Letters by Case
/**
*@param chars: The letter array you should sort by Case
*@return: void
*/
public void sortLetters(char[] chars) {
if(chars == null || chars.length == 0)
return;
int lower = 0;
for(int i = 0; i < chars.length; i++) {
if(chars[i] - 'a' >= 0 && chars[i] - 'a' <= 26) {
if(i > lower) {
char tmp = chars[i];
chars[i--] = chars[lower];
chars[lower] = tmp;
}
lower++;
}
}
}
94
Binary Search
95
Closest Number
Given an unsorted array, find out the most closest two elements in this array.
Solution:
Sort is important here! You must think about sort first. Since other may may
cost
Then the gap between adjacent elements are the
96
3 Sum Smaller
3Sum Smaller
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 .
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]
Think
Set iterate from rear.
One tricky pattern:
When nums[l] + nums[r] +nums[i] < target , all for combinations
like: nums[l] + nums[r-1] +nums[i] < target , nums[l] +
nums[r-2] +nums[i] < target , ..., nums[l] + nums[l+1] +nums[i]
< target are workable.
So result counter should directly add the r - l
All in all, two cases:
nums[l] + nums[r] +nums[i] < target , add the cnt and move the
l
nums[l] + nums[r] +nums[i] >= target , just move the r
It is not very similar like binary search but still has kinda idea inside.
Solution
97
3 Sum Smaller
98
Count Smaller Number
Give you an integer array (index from 0 to n-1, where n is the size of this array,
value from 0 to 10000) and an query list. For each query, give you an integer,
return the number of element in the array that are smaller that the given integer.
Example
For array [1,2,7,8,5] , and queries [1,8,5] , return [0,4,2]
Challenge
Could you use three ways to do it.
Just loop
Sort and binary search
Solution
99
Count Smaller Number
100
Count Smaller Number
Arrays.sort(A);
for(int i = 0; i < queries.length; i++) {
int cnt = binarySearch(A, queries[i]);
res.add(cnt);
}
return res;
}
101
Triangle Count
Triangle Count
Given an array of integers, how many three numbers can be found in the array, so
that we can build an triangle whose three edges length is the three numbers that
we find?
Example
Given array S = [3,4,6,7], return 3. They are:
[3,4,6]
[3,6,7]
[4,6,7]
[4(1),4(2),4(3)]
[4(1),4(2),4(4)]
[4(1),4(3),4(4)]
[4(2),4(3),4(4)]
Think
Sort
Binary Search
But how to define driven condition? (Tricky Part)
As we know, triangle is made by i + j > k ;
So we capture the largest one [k] (passing from length - 1 to 2 )
Get left = 0 and right = k - 1
If [left] + [right] > [k] , that means in the segment, [left]
can be valued between [left] and [right-1] , all of that can make
valid triangle. So count += right - left !
If [left] + [right] <= [k] , just make the left increase to detect
any valid possibility.
102
Triangle Count
Solution
103
Recursion
Recursion
Space
Recursion is consuming the stack space in JVM or other programming stack. So
we care how deep the recursion functions are going on and we need to set a
smart terminate condition for recursion.
Time
Pruning! Pruning is important when doing a complex recursion function. We can
avoid some unnecessary recursion by terminate it with smart condition.
104
Print Numbers by Recursion
Example
Given N = 1 , return [1,2,3,4,5,6,7,8,9] .
Note
It's pretty easy to do recursion like:
recursion(i) {
if i > largest number:
return
results.add(i)
recursion(i + 1)
}
However this cost a lot of recursion memory as the recursion depth maybe very
large ( ). Can you do it in another way to recursive with at most N depth?
Challenge
Do it in recursion, not for-loop.
Think
Think from bottom to top.
Build the result list from number with one digits to N digits.
Since we considering with digits as its deep, we have to set a loop to add the
number in list on the new-generated base number (1 - 9 with following digits):
105
Print Numbers by Recursion
Each time when having the new-generated base number, we need to pass
through the original result list to fill the rest of number with beginning as new-
generated base number.
Solution
106
Print Numbers by Recursion
Complexity Analysis
Time:
Space:
107
Permutation
108
Permutation Index I
Permutation Index
Given a permutation which contains no repeated number, find its index in all the
permutations of these numbers, which are ordered in lexicographical order. The
index begins at 1.
Example
Given [1,2,4] , return 1 .
Thinking
Illustrating by manually getting the index of {2, 4, 3, 1}. Since this is a 4-element
set, we know there are 4! permutations (4! = 4321). If the set only had 3 elements,
we would have 321 permutations. If the set only had 2 elements, we would have
2!=21 permutations; and so on.
If we treat our 4-element set as a positional system, then we get the following
positional weights: 3!, 2!, 1!, 0. So that the index of {2, 4, 3, 1} is: x3!+y2!+z1!+w0.
Presently it suffices to find the values of x,y,z to calculate the index (we ignore w
because it is paired with 0). x,y,z are counters: the number of succeeding
elements less than the element being considered. For example, in {2, 4, 3, 1},
there are two succeeding elements less than 4 (namely 3 and 1). For 2 it's 1 (1);
for 4 it's 2 (3 and 1); for 3 it's 1 (1); for 1 it's 0. Now we can calculate the index of
{2, 4, 3, 1} as: x=1, y=2, z=1: x*3!+y*2!+z*1!+w*0 = 1*3! + 2*2! + 1*1! =
6 + 4 + 1 = 11 .
The key is counting from low digit(right) to higher digit(left), and checking how
many digits are less than current digits. Then using that count as the
coefficient with positional weight.
109
Permutation Index I
Solution
int pos = 2;
long factor = 1;
long index = 1;
for(int i = A.length - 2; i >= 0; i--) {
int cnt = 0;
for(int j = i + 1; j < A.length; j++) {
if(A[i] > A[j])
cnt++;
}
index += (cnt*factor);
factor *= pos;
pos++;
}
return index;
}
}
Complexity Analysis
Two loop: i range 0 -> length - 2 and j range i + 1 -> length - 1 ,
So it is O(n^2) ; Constant Space with some integer variable, Space: O(1) ;
110
Permutation Index II
Permutation Index II
Given a permutation which may contain repeated numbers, find its index in all the
permutations of these numbers, which are ordered in lexicographical order. The
index begins at 1.
Example
Given the permutation [1, 4, 2, 2] , return 3 .
Think
The key is counting from low digit(right) to higher digit(left), and checking how
many digits are less than current digits. Then using that count as the coefficient
with positional weight. However, there are duplicates occured. So that means we
can use a hash map to do the count. But the positional system should be
modified. The multiple of the factorial of the duplicates occurence should be
divided by original position system. That means the entry.value need to to the
factorial and multiply those factors. Why? For example, n numbers with 2
duplicates, like 2,4,3,3 , when 4
Solution
int pos = 2;
long factor = 1;
111
Permutation Index II
long index = 1;
for(int i = A.length - 2; i >= 0; i--) {
HashMap<Integer, Integer> map = new HashMap<>();
int cnt = 0;
// count itself
map.put(A[i], 1);
for(int j = i + 1; j < A.length; j++) {
// count all occurence on following element in A
rray
map.put(A[j], map.containsKey(A[j])?map.get(A[j]
)+1:1);
if(A[i] > A[j])
cnt++;
}
index += (cnt*factor)/factorialMultiple(map);
factor *= pos;
pos++;
}
return index;
}
112
Permutation Index II
113
Permutation Sequence
Permutation Sequence
Given n and k, return the k-th permutation sequence.
Example
For n = 3, all permutations are listed as follows:
"123"
"132"
"213"
"231"
"312"
"321"
Note
n will be between 1 and 9 inclusive.
Challenge
O(n*k) in time complexity is easy, can you do it in O(n^2) or less?
Think
a1,a2,a3.....an的permutation 如果确定了a1,那么剩下的permutation就有(n-1)!种 所
以 a1 = k / (n-1)! k2 = k % (n-1)! a2 = k2 / (n-2)!
要注意的是
得到的应该是剩下选择数字的index,而不是value,所以要建一个存储可用数字的
list
在用完一个数字后要将它从list中删去
114
Permutation Sequence
Solution
class Solution {
/**
* @param n: n
* @param k: the kth permutation
* @return: return the k-th permutation
*/
public String getPermutation(int n, int k) {
115
Permutation Sequence
116
Next Permutation
Next Permutation
Given a list of integers, which denote a permutation.
Example
For [1,3,2,3] , the next permutation is [1,3,3,2] For [4,3,2,1] , the
next permutation is [1,2,3,4]
Note
The list may contains duplicate integers.
Think
字典序算法:
Solution
117
Next Permutation
return nums;
}
118
Next Permutation
Complexity Analysis
At most, two pass o(2*n) -> O(n); Constant Space Complexity: O(1)
119
Previous Permutation
Previous Permutation
Given a list of integers, which denote a permutation.
Example
For [1,3,2,3] , the previous permutation is [1,2,3,3]
Note
The list may contains duplicate integers.
Think
step 1: find last nums[k] > nums[k + 1];
step 2: find last nums[i] < nums[k];
step 3: swap i, j;
step 4: reverse num after i;
Solution
120
Previous Permutation
// step 3: swap i, j
Collections.swap(nums, i, j);
return nums;
}
121
Previous Permutation
122
Backtracking
123
K Sum II
K Sum II
Given n unique integers, number k (1<=k<=n) and target. Find all possible k
integers where their sum is target.
Example
Given [1,2,3,4], k=2, target=5, [1,4] and [2,3] are possible solutions.
Think
Unlike the k Sum I, here we need to get the each solution which can achieve the
target within k values. Since the solution should be shown in the result, the
dynamic programming cannot be used. Thus, the backtracking should be the only
way.
Solution
124
K Sum II
if(target == 0 && k == 0) {
res.add(new ArrayList<>(cur));
return;
}
125
N Queen I
Example
There exist two distinct solutions to the 4-queens puzzle:
[".Q..", // Solution 1
"...Q",
"Q...",
"..Q."],
["..Q.", // Solution 2
"Q...",
"...Q",
".Q.."]
Think
To save the space, use one dimension integer array to represent board: index
-> num, value -> col;
126
N Queen I
. . Q . .
. . . . Q
Q . . . . ----->>>> {2, 4, 0, 3, 1}
. . . Q .
. Q . . .
Solution
class Solution {
/**
* Get all distinct N-Queen solutions
* @param n: The number of queens
* @return: All distinct solutions
* For example, A string '...Q' shows a queen on forth posit
ion
*/
ArrayList<ArrayList<String>> solveNQueens(int n) {
ArrayList<ArrayList<String>> res = new ArrayList<>();
int[] board = new int[n];
recursion(res, board, 0);
return res;
}
127
N Queen I
}
cur.add(sb.toString());
}
res.add(cur);
return;
}
// recursion
for(int i = 0; i < board.length; i++) {
board[row] = i;
if(isSafe(board, row))
recursion(res, board, row+1);
}
/**
* Check the current board is safe.
*/
private boolean isSafe(int[] board, int row) {
for(int i = 0; i < row; i++) {
// difference on col value shouldn't equal to the di
fference on row value;
if((board[i]==board[row]) || (Math.abs(i - row) == M
ath.abs(board[i] - board[row])))
return false;
}
return true;
}
};
128
N Queen II
N Queen II
Follow up for N-Queens problem.
Now, instead outputting board configurations, return the total number of distinct
solutions.
Solution
129
N Queen II
class Solution {
/**
* Calculate the total number of distinct N-Queen solutions.
* @param n: The number of queens.
* @return: The total number of distinct solutions.
*/
private int solutions = 0;
public int totalNQueens(int n) {
//write your code here
int[] board = new int[n];
recursion(board, 0);
return solutions;
}
130
N Queen II
131
Subsets
Subset
Given a set of distinct integers, return all possible subsets.
Example
If S = [1,2,3] , a solution is:
[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
]
Note
Elements in a subset must be in non-descending order.
For Question I: The solution set must not contain duplicate subsets. For Question
II: The solution set may contain duplicate subsets.
Solution
// Question I:
public class Solution {
/**
* Recursive method, backtracking with a boolean array
**/
public ArrayList<ArrayList<Integer>> subsets(int[] num) {
132
Subsets
/**
* Iterate method, a loop and retreve the value in original l
ist and generate new value with insert it
**/
public ArrayList<ArrayList<Integer>> subsets(int[] num) {
ArrayList<ArrayList<Integer>> res = new ArrayList<ArrayL
ist<Integer>>();
if(num == null || num.length == 0)
return res;
ArrayList<Integer> list = new ArrayList<Integer>();
Arrays.sort(num);
res.add(list);
for(int i = 0; i < num.length; i++) {
int size = res.size();
for(int j = 0; j < size; j++) {
list = new ArrayList<>(res.get(j));
list.add(num[i]);
res.add(list);
}
}
133
Subsets
return res;
}
}
// Question II:
public class Solution {
public ArrayList<ArrayList<Integer>> subsetsWithDup(ArrayLis
t<Integer> num) {
ArrayList<ArrayList<Integer>> result = new ArrayList<Arr
ayList<Integer>>();
if(num == null || num.size() == 0) {
return result;
}
ArrayList<Integer> list = new ArrayList<Integer>();
Collections.sort(num);
subsetsHelper(result, list, num, 0);
return result;
}
result.add(new ArrayList<Integer>(list));
134
Subsets
135
Phone Number
Phone Number
Given a digit string, return all possible letter combinations that the number could
represent.
Example
Given 23
Return ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"]
Note
Although the above answer is in lexicographical order, your answer could be in
any order you want.
Solution
136
Phone Number
137
Boggle Game
Boggle Game
Given a dictionary, a method to do lookup in dictionary and a M x N board where
every cell has one character. Find all possible words that can be formed by a
sequence of adjacent characters. Note that we can move to any of 8 adjacent
characters, but a word should not have multiple instances of same cell.
Think
DFS on character board to do backtracking.
Searching the character for 8 directions.
Mark the visited position by a boolean board (Takes O( ) space)
Solution
138
Boggle Game
if(dict.contains(cur)) {
res.add(cur);
dict.remvoe(cur);
return;
}
// 8 - direction
int[] xs = {1,1,1,0,0,-1,-1,-1};
int[] ys = {1,-1,0,1,-1,0,1,-1};
for(int i = 0; i < 8; i++) {
int nx = xs[i] + x;
int ny = ys[i] + y;
if(nx >= 0 && nx < board.length && ny >= 0 && ny < b
oard[nx].length && !visited[nx][ny])
findUtil(res, dict, board, visited, cur, nx, ny)
;
}
visited[x][y] = false;
cur = cur.substring(0, cur.length() - 1);
}
139
Scramble Number Pair Calculator
Given integers A and B with the same number of digits and no leading zeroes,
how many distinct scrambled pairs (i, j) are there that satisfy: A <= i < j <= B?
Example
For instance, if we let A = 10 and B = 99, the answer is 36:
140
Scramble Number Pair Calculator
/**
* Main function to do the scramble number pair calculation
* @param minRange : minimum of range
* @param maxRange : maximum of range
* @return
*/
public static long scrambleNumberCalculator(int min, int ma
x) {
// the total scramble number set to avoid duplicate calc
ulate
Set<Integer> pairs = new HashSet<>();
/**
* The function to check current number has how many scrambl
e number and store it in a set,
* recursion without return value but values are recorded in
permutation set
*
141
Scramble Number Pair Calculator
/**
* The function to count the pair amount in permutation set
by just using the size of current scramble number set
* @param num: consider the large input I use long type here
* @return the amount of pair in current permutation set
*/
private static long combinationPair(long num) {
long pairCnt = 0;
for (int i = 0; i < num - 1; i++)
for (int j = i + 1; j < num; j++)
pairCnt++;
return pairCnt;
}
142
Scramble Number Pair Calculator
/**
* The function to convert a number into a list with digits
make the permutation more convenient
* @param num
* @return
*/
private static List<Integer> convertDigitsList(int num) {
List<Integer> res = new LinkedList<>();
while (num > 0) {
res.add(0, num % 10);
num /= 10;
}
return res;
}
}
143
Strobogrammatic Number
Strobogrammatic Number
Problem I
A strobogrammatic number is a number that looks the same when rotated 180
degrees (looked at upside down).
For example, the numbers "69" , "88" , and "818" are all strobogrammatic.
Solution
144
Strobogrammatic Number
// Use HashMap
public boolean isStrobogrammatic(String num) {
if(num == null || num.length() == 0) {
return true;
}
int lo = 0;
int hi = num.length() - 1;
lo++;
hi--;
}
return true;
}
}
Problem II
145
Strobogrammatic Number
A strobogrammatic number is a number that looks the same when rotated 180
degrees (looked at upside down). Find all strobogrammatic numbers that are of
length = n.
Example,
Given n = 2, return ["11","69","88","96"] .
Think
Typical backtracking to generate something question
Solution
146
Strobogrammatic Number
Problem III
147
Strobogrammatic Number
A strobogrammatic number is a number that looks the same when rotated 180
degrees (looked at upside down).
Write a function to count the total strobogrammatic numbers that exist in the range
of low <= num <= high.
Example
Given low = "50", high = "100", return 3. Because 69, 88, and 96 are three
strobogrammatic numbers.
Note
Because the range might be a large number, the low and high numbers are
represented as string.
Solution
148
Strobogrammatic Number
149
Factor Combinations
Factor Combinations
Numbers can be regarded as product of its factors. For example,
8 = 2 x 2 x 2;
= 2 x 4.
Write a function that takes an integer n and return all possible combinations of its
factors.
Note
Each combination’s factors must be sorted ascending, for example: The factors of
2 and 6 is [2, 6] , not [6, 2] .
Examples
input: 1
output: []
input: 37
output: []
input: 12
input: 32
output: [ [2, 16], [2, 2, 8], [2, 2, 2, 4], [2, 2, 2, 2, 2], [2, 4,
4], [4, 8] ]
150
Factor Combinations
Think
For input value n , it has possible factors start from 2 to Sqrt(n)
For every factor, we also calculate its factors, like: 16 -> 2, 8 -> 2, 2, 4
-> 2, 2, 2, 2, 2
Build helper function, the only difference between main recursion and helper
recursion function is, in helper, we have to consider about the input value is
one of factor which should also include in result list
Solution
151
Factor Combinations
152
Factor Combinations
153
Dynamic Programming
Dynamic Programming
Function
How to pass through the memorial data structure?
Initialization
How to start the memorizing procedure and think about the boundary conditions?
Answer
154
Dynamic Programming
Where is answer? Is it the last element in memorial data? Or it need to record any
maximum or minimum value?
Routines
Matrix DP (2-D memorized)
Status: f[i][j] means to get the value by the start point to the position
[i][j]
155
Dynamic Programming
Status: f[i][j] means the first [i] number/alphabet and first [j]
number/alphabet
156
Home Robber
House Robber
You are a professional robber planning to rob houses along a street. Each house
has a certain amount of money stashed, the only constraint stopping you from
robbing each of them is that adjacent houses have security system connected and
it will automatically contact the police if two adjacent houses were broken
into on the same night.
Example
Given [3, 8, 4] , return 8.
Challenge
time and memory.
Think
When Rob meet a house, he has two choices: taken or not taken, but if he
had stolen the previous house, it cannnot taken.
Set two variable: include and exclude
include means it has taken the previous house, while the exclude
means it didn't take in previous house.
So each time we consider about the exclude + cur_value and
include , the max of them should be new include while the new
exclude come from the max value of original include (last taken,
current not taken) and original exclude (not taken in both last and current
house)
Solution
157
Home Robber
/**
* @param A: An array of non-negative integers.
* return: The maximum amount of money you can rob tonight
*/
public long houseRobber(int[] A) {
if(A == null)
return 0L;
long exclude = 0L;
long include = 0L;
Follow Up
After robbing those houses on that street, the thief has found himself a new place
for his thievery so that he will not get too much attention. This time, all houses at
this place are arranged in a circle. That means the first house is the neighbor of
the last one. Meanwhile, the security system for these houses remain the same as
for those in the previous street.
Think
The houses are in a cycle,so that when pick up the first element we cannot pick
the last element because they are adjacent. So just seperate two parts for
calculating: 0 to last second element , and 1 to last element , find the
maximum from them.
158
Home Robber
Solution
159
Backpack I
Backpack I
Given n items with size Ai, an integer m denotes the size of a backpack. How full
you can fill this backpack?
Example
If we have 4 items with size [2, 3, 5, 7], the backpack size is 11, we can select [2,
3, 5], so that the max size we can fill this backpack is 10. If the backpack size is
12. we can select [2, 3, 7] so that we can fulfill the backpack.
You function should return the max size we can fill in the given backpack.
Note
You can not divide any item into small pieces.
Challenge
time and memory.
Think
Setup 2-D memorized array with length is memo[items.length][bag
size]
memo[i][S] means what is the max size we can fill in when get first i items.
Then we should check from zero to M size when got i th items and
evaluate the max size when taken or not taken current i th item.
Solution
160
Backpack I
/**
* @param m: An integer m denotes the size of a backpack
* @param A: Given n items with size A[i]
* @return: The maximum size
*/
public int backPack(int M, int[] A) {
int[][] bp = new int[N + 1][M + 1];
161
Backpack II
Backpack II
Given n items with size Ai and value Vi, and a backpack with size m. What's the
maximum value can you put into the backpack?
Example
Given 4 items with size [2, 3, 5, 7] and value [1, 5, 2, 4] , and a
backpack with size 10 . The maximum value is 9 .
Note
You cannot divide item into small pieces and the total size of items you choose
should smaller or equal to m.
Challenge
memory is acceptable, can you do it in memory?
Think
The same idea as the Backpack I.
But the value on memo array should be the value of items in bag
Solution
162
Backpack II
/**
* @param m: An integer m denotes the size of a backpack
* @param A & V: Given n items with size A[i] and value V[i]
* @return: The maximum value
*/
public int backPackII(int m, int[] A, int V[]) {
// write your code here
int[][] memo = new int[A.length+1][m+1];
return memo[A.length][m];
}
Solution
163
Backpack II
/**
* @param m: An integer m denotes the size of a backpack
* @param A & V: Given n items with size A[i] and value V[i]
* @return: The maximum value
*/
public int backPackII(int m, int[] A, int V[]) {
// write your code here
int[] memo = new int[m+1];
int maxVal = 0;
for(int i = m; i >= 0; i--)
maxVal = Math.max(maxVal, memo[i]);
return maxVal;
}
164
Edit Distance
Edit Distance
Given two words word1 and word2, find the minimum number of steps required to
convert word1 to word2. (each operation is counted as 1 step.)
Insert a character
Delete a character
Replace a character
Example
Given word1 = mart and word2 = karma , return 3 .
Think
Two sequence DP
Setup a 2-D array
memo[i][j] means the edit distance between word1(1, i) and
word2(1, j) on the current position.
When word1[i] != word2[j] , it need increase the distance, so the value
of memo[i][j] comes from the minimum of memo[i-1][j] , memo[i][j-
1] or memo[i-1][j-1] then plus one.
Initialized value is i or j when word1(0,0) or word2(0,0)
( memo[i][0] or memo[0][j] )
The final output is memo[word1.length][word2.length]
Solution
165
Edit Distance
/**
* @param word1 & word2: Two string.
* @return: The minimum number of steps.
*/
public int minDistance(String A, String B) {
// write your code here
if(A == null || B == null)
return 0;
166
Longest Increasing Subsequence
Example
Given [10, 9, 2, 5, 3, 7, 101, 18] , The longest increasing sub-sequence
is [2, 3, 7, 101] , therefore the length is 4 . Note that there may be more
than one LIS combination, it is only necessary for you to return the length.
Follow up
Improve it to O(n log n) time complexity?
Think #1
Setup one dimensional array to memorize the longest sub-sequence on each
element
One pass on each element,
But it need to go through the previous indexes to check any elements less
than current element and compare the maximum by max(current, prev
+1)
Solution #1
167
Longest Increasing Subsequence
/**
* @param nums: The integer array
* @return: The length of LIS (longest increasing subsequenc
e)
*/
public int longestIncreasingSubsequence(int[] nums) {
if(nums == null || nums.length == 0)
return 0;
int[] memo = new int[nums.length];
int max = 0;
for(int i = 0; i < nums.length; i ++) {
memo[i] = 1;
for(int j = 0; j < i; j++) {
if(nums[j] < nums[i]) {
memo[i] = Math.max(memo[i], memo[j] + 1);
}
max = Math.max(memo[i], max);
}
}
return max;
}
Think #2
Setup an array table with the length of nums
One pass on each element and initial max cursor is 0 in table
Replace the element in table is just larger than current passing element
If current element is largest, increase the cursor in table
Finally, the the cursor + 1 is the max length.
Solution #2
/**
* @param nums: The integer array
* @return: The length of LIS (longest increasing subsequenc
e)
168
Longest Increasing Subsequence
*/
public int longestIncreasingSubsequence(int[] nums) {
if(nums == null || nums.length == 0)
return 0;
int[] memo = new int[nums.length];
int max = 0;
memo[0] = nums[0];
for(int i = 1; i < nums.length; i++) {
if(nums[i] < memo[0])
memo[0] = nums[i];
else if(memo[max] <= nums[i])
// equal or not depend on question requirement
memo[++max] = nums[i];
else{
int idx = findCeil(memo, max, nums[i]);
memo[idx] = nums[i];
}
}
return ++max;
}
/**
* @param arr: the memo array
* @param right index: current max in the memo array
* @param val: target value
* @return: where should val put in memo array
*/
private int findCeil(int[] arr, int r, int val){
int l = 0;
while(l + 1 < r) {
int m = l + ((r - l)>>1);
if(arr[m] < val)
l = m;
else
r = m;
}
return r;
}
169
Longest Increasing Subsequence
170
Minimum Adjustment Cost
If the array before adjustment is A, the array after adjustment is B , you should
minimize the sum of |A[i]-B[i]|
Example
Given [1,4,2,3] and target = 1, one of the solutions is [2,3,2,3] , the
adjustment cost is 2 and it's minimal.
Return 2 .
Note You can assume each number in the array is a positive integer and not
greater than 100 .
Think
There is invisible condition on Note part: each number in the array is a
positive integer and not greater than 100
So the above condition giving the memorized data structure a length on
enumeration.
memo data should be memo[arr.size() + 1][100] , which means the
minimum cost on modify the ith num in A to j
Pass each element in input array
Then enumeration j on 0 to 99, so that we can consider the previous
number p should inside the range between j + target and j-
target .
So the previous cost should be memo[i-1][p] and for current, it should be
memo[i-1][p] + Math.abs(j-A.get(i-1))
After arrived the last element and got all possible cost, the minimum total cost
should come from memo[last element][i]
171
Minimum Adjustment Cost
Solution
/**
* @param A: An integer array.
* @param target: An integer.
*/
public int MinAdjustmentCost(ArrayList<Integer> A, int targe
t) {
// the minimum cost on modify the ith num in A to j
int[][] memo = new int[A.size() + 1][100];
172
Minimum Adjustment Cost
173
Coins in A Line (I ~ III)
Coins in a Line
Problem I
There are n coins in a line. Two players take turns to take one or two coins from
right side until there are no more coins left. The player who take the last coin wins.
Could you please decide the first play will win or lose?
Example
n = 1 , return true .
n = 2 , return true .
n = 3 , return false .
n = 4 , return true .
n = 5 , return true .
Challenge
time and memory
Think
Only if the amount of coin is the multiply of 3 , first player cannot win.
Solution
174
Coins in A Line (I ~ III)
/**
* @param n: an integer
* @return: a boolean which equals to true if the first play
er will win
*/
public boolean firstWillWin(int n) {
return n%3!=0;
}
Problem II
There are n coins with different value in a line. Two players take turns to take one
or two coins from left side until there are no more coins left. The player who take
the coins with the most value wins.
Could you please decide the first player will win or lose?
Example
Given values array A = [1,2,2] , return true.
Think
State
dp[i] represent the max value it can get from i to the end
Function
takes values[i]
takes values[i] + values[i+1]
175
Coins in A Line (I ~ III)
3.
Solution
176
Coins in A Line (I ~ III)
/**
* @param values: an array of integers
* @return: a boolean which equals to true if the first play
er will win
*/
public boolean firstWillWin(int[] values) {
if (values == null || values.length <= 2) {
return true;
}
int dp[] = new int[values.length];
dp[values.length-1] = values[values.length-1];
dp[values.length-2] = values[values.length-1] + values[v
alues.length-2];
int total = dp[values.length-2];
Problem III
There are n coins in a line. Two players take turns to take a coin from one of the
ends of the line until there are no more coins left. The player with the larger
amount of money wins.
Could you please decide the first player will win or lose?
Example
177
Coins in A Line (I ~ III)
Challenge
Follow Up Question: If n is even. Is there any hacky algorithm that can decide
whether first player will win or lose in memory and time?
Think
State
Function
takes values[i]
takes values[j]
Solution
178
Coins in A Line (I ~ III)
/**
* @param values: an array of integers
* @return: a boolean which equals to true if the first play
er will win
*/
public boolean firstWillWin(int[] values) {
if (values == null || values.length <= 2) {
return true;
}
// to do the dp
for(int i = values.length - 1; i >= 0; i--){
for(int j = i; j < values.length; j++) {
if(i == j)
dp[i][j] = values[i];
else
dp[i][j] = sum[i][j] - Math.min(dp[i+1][j],d
p[i][j-1]);
}
}
179
Coins in A Line (I ~ III)
180
Distinct Subsequences
Distinct Subsequences
Given a string S and a string T, count the number of distinct subsequences of T in
S.
A subsequence of a string is a new string which is formed from the original string
by deleting some (can be none) of the characters without disturbing the relative
positions of the remaining characters. (ie, "ACE" is a subsequence of "ABCDE"
while "AEC" is not).
Example
Given S = "rabbbit", T = "rabbit", return 3.
Challenge
Do it in time and memory.
Think
Two sequence DP, setup 2-D array for memorizing
dp[i][j] means the distinct count when S(1,i) and T(1,j)
If S has non character dp[0][j] should be 0, while T has non character
dp[i][0] should be 1.
Each time we add S[i] on dp[i-1][j] , iterate j from 0 to len -
1 , if S[i] == T[j] we should look up the the result from dp[i-1][j-1]
and add it on dp[i-1][j] , otherwise we add nothing.
Solution
181
Distinct Subsequences
/**
* @param S, T: Two string.
* @return: Count the number of distinct subsequences
*/
public int numDistinct(String S, String T) {
int[][] memo = new int[S.length() + 1][T.length() + 1];
for(int i = 0; i <= S.length(); i++) {
for(int j = 0; j <= T.length(); j++) {
if(i == 0)
memo[i][j] = 0;
if(j == 0)
memo[i][j] = 1;
else{
memo[i][j] = memo[i-1][j] + (S.charAt(i-1) =
= T.charAt(j-1)) ? memo[i-1][j-1] : 0;
}
}
}
return memo[S.length()][T.length()];
}
182
Maximal Square
Maximal Square
Given a 2D binary matrix filled with 0's and 1's, find the largest square containing
all 1's and return its area.
Example
For example, given the following matrix:
1 0 1 0 0
1 0 1 1 1
1 1 1 1 1
1 0 0 1 0
Return 4 .
Think
Use itself as memorized array (modifying value directly on matrix)
Ignore the top and left boundary
If current point [i][j] is one, look up all three directions from [i-1][j] ,
[i-1][j-1] and [i][j-1] are not zero, get the minimum value from
them so that the value plus one is the maximum length of square on current
point.
However, if one of three is zero, current point should keep zero or one
Set a max value to track the max length.
Don't forget make a square on final max result, since that result is just for
length
Solution
183
Maximal Square
/**
* @param matrix: a matrix of 0 and 1
* @return: an integer
*/
public int maxSquare(int[][] matrix) {
if(matrix == null || matrix.length == 0)
return 0;
int max = 0;
for(int i = 0; i < matrix.length; i++) {
for(int j = 0; j < matrix[i].length; j++) {
if(i != 0 && j != 0 && matrix[i][j]!=0 && matrix
[i-1][j] != 0 && matrix[i][j-1] != 0 && matrix[i-1][j-1] != 0)
matrix[i][j] = 1 + Math.min(matrix[i-1][j-1]
,Math.min(matrix[i-1][j],matrix[i][j-1]));
max = Math.max(max, matrix[i][j]);
}
}
return max*max;
}
184
Interleaving String
Interleaving String
Given three strings: s1, s2, s3, determine whether s3 is formed by the interleaving
of s1 and s2.
Example
For s1 = "aabcc" , s2 = "dbbca"
Challenge
time or better
Think
Two sequence DP, 2-D memorized boolean array
memo[i][j] means from word1(1,i) and word2(1,j) can form the
word3(1, i+j)
Initial the case memo[0][j] and memo[i][0] is false and memo[0][0]
should be true.
Pass through i from 0 to word1.length and j from 0 to
word2.length , check if word3[i+j-1]== word2[j-1] or word3[i+j-
1]== word1[i-1]
We also have to make sure when word3[i+j-1]== word2[j-1] , the
memo[i][j-1] should be true or word3[i+j-1]== word1[i-1] , the
memo[i-1][j] should be true
Get the memo[len1][len2] as the final boolean result
Solution
185
Interleaving String
/**
* Determine whether s3 is formed by interleaving of s1 and
s2.
* @param s1, s2, s3: As description.
* @return: true or false.
*/
public boolean isInterleave(String s1, String s2, String s3)
{
return memo[s1.length()][s2.length()];
}
186
Word Break
Word Break
Given a string s and a dictionary of words dict, determine if s can be break into a
space-separated sequence of one or more dictionary words.
Example
Given s = "lintcode" , dict = ["lint", "code"] .
Think
One sequence DP, a 1-D boolean array.
memo[i] means from 0 to i has valid word break or not.
Tricky part is when we pass at i position, we don't need to use j from
0 to i for checking word existed in dictionary. We can use the length of
word in dictionary as an length evaluation.
Solution
187
Word Break
/**
* @param s: A string s
* @param dict: A dictionary of words dict
*/
public boolean wordBreak(String s, Set<String> dict) {
188
Scramble String
Scramble String
Given a string s1, we may represent it as a binary tree by partitioning it to two
non-empty substrings recursively.
great
/ \
gr eat
/ \ / \
g r e at
/ \
a t
To scramble the string, we may choose any non-leaf node and swap its two
children.
For example, if we choose the node "gr" and swap its two children, it produces a
scrambled string "rgeat" .
rgeat
/ \
rg eat
/ \ / \
r g e at
/ \
a t
Similarly, if we continue to swap the children of nodes "eat" and "at", it produces a
scrambled string "rgtae" .
189
Scramble String
rgtae
/ \
rg tae
/ \ / \
r g ta e
/ \
t a
Think - DP Version
Ignore two situations: both length not equal and the characters not the same
Two sequence but 3-D memorized array
memo[i][j][k] means state: for s1.substring(i, i + k) and s2.substring(j, j +
k), if they are scramble string
Two conditions we can regard as scramble, for range of word1(i -> i+k)
or word2(j -> j+k) :
i -> i + split = j -> j + split (len = split) and split + i -
> i + k = split + i -> j + k (len = k - split)
i -> i + split = j + (k - split) -> j+k [len = split] and i +
split -> i+k = j -> j + (k - split) (len = k - split)
Consider about the initialization:
for k == 1 , we only check if word1[i] == word2[j]
Solution
/**
* @param s1 A string
* @param s2 Another string
* @return whether s2 is a scrambled string of s1
*/
public boolean isScramble(String s1, String s2) {
190
Scramble String
// check length
if(s1==null||s2==null||s1.length()!=s2.length())
return false;
// check anagram
char[] c1 = s1.toCharArray();
char[] c2 = s2.toCharArray();
Arrays.sort(c1);
Arrays.sort(c2);
if (!Arrays.equals(c1, c2))
return false;
if(s1.length() != s2.length())
return false;
int len = s1.length();
191
Scramble String
192
Maximum Subarray III
Example
Given [-1,4,-2,3,-2,3] , k= 2 , return 8
Note
The subarray should contain at least one number
Think
State: memo[k][i] means the max subarray sum value from index 0 to i-1
with taken k subarrays
Since k is the amount of subarray, so at least we have to take k
elements in array
Initilize with two case:
Taken first k elements, each element is a subarray, so we only
consider first kth element.
Taken only one subarray, with two cases: start from previous to current or
start from itself.
For the rest of elements, consider two cases:
Taken from the previous element with no subarray amount increase
( memo[k][i-1] + current element )
Taken from current element but increase k so memo[k-1][n] +
current element , however, here n can be any number from k-1
to current index - 1
193
Maximum Subarray III
Solution
194
Maximum Subarray III
195
Paint House
Painter Problems
Paint Fence
There is a fence with n posts, each post can be painted with one of the k
colors.
You have to paint all the posts such that no more than two adjacent fence
posts have the same color.
Return the total number of ways you can paint the fence.
Note
n and k are non-negative integers.
Think
Two cases:
If [n-1] == [n] , [n] has 1 choices
If [n-1] != [n] , [n] has k-1 choices with consider the result
from both [n-2] == [n-1] OR [n-2] != [n-1] .
Solution
196
Paint House
Paint House
There are a row of n houses, each house can be painted with one of the three
colors: red , blue or green . The cost of painting each house with a certain
color is different. You have to paint all the houses such that no two adjacent
houses have the same color.
197
Paint House
Think
Current paint only come from the previous different paint cost
minCost[i][j] = costs[i][j] + min(minCost[i-1][k]) (k != j)
We can do it in-place, update the newest value on the original memorized
array.
int max = 0;
for(int i = 0; i < costs[costs.length - 1].length; i++)
max = Math.max(max, costs[costs.length - 1][i]);
return max;
}
198
Linked List
Linked List
Linked List is common data structure:
But it covers a lot of algorithm strategies with manipulating this kind of data
structure.
Routines
Two Pointers
Runner Node and Walker Node
Find a certain point in list
e.g. Remove Nth Node from End of List
e.g. Palindrome List
Find Cycle in Linked List
Reverse Node
Remove Duplicates in List
Dummy Node
e.g. Copy Random Pointer on Linked List
Sort Algorithms
e.g. Insertion Sort on Linked List
e.g. Merge K Sorted Linked List (Assisted with Heap)
Divide and Conquer
e.g. Merge Sort Linked List
e.g. Build a Tree from Linked List
199
Linked List
200
Remove Linked List Element
Solution
201
Remove Nth Element from End of List
Example
Given linked list: 1->2->3->4->5->null , and n = 2 .
After removing the second node from the end, the linked list becomes 1->2->3-
>5->null .
Note
The minimum number of nodes in list is n.
Challenge
O(n) time
Think
Typical idea on runner and walker linked list question
Let runner node run for N step further than walker node.
Get the N + 1 th position from end of list.
Remove walker.next which is the target node.
Solution
202
Remove Nth Element from End of List
203
Swap Nodes by Pairs in Linked List
Example
Given 1->2->3->4, you should return the list as 2->1->4->3.
Challenge
Your algorithm should use only constant space. You may not modify the values in
the list, only nodes itself can be changed.
Think
Record next two node: dummy pre -> A -> B -> C .
Get C as next, change pre.next to B(head.next), B.next to A(head) and
A(head.next) to C.
Do while loop when head and head.next are both not null node
Solution
204
Swap Nodes by Pairs in Linked List
205
Intersection of Linked List
Example
The following two linked lists:
A: a1 → a2
↘
c1 → c2 → c3
↗
B: b1 → b2 → b3
Note
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.
Think
Count the length of each linked list
Make two counts to be equal, then start moving and check if there are two
nodes the same as each other.
Solution
206
Intersection of Linked List
ListNode a = headA;
ListNode b = headB;
int alen = 0, blen = 0;
while(a!=null) {
a = a.next;
alen++;
}
while(b!=null) {
b = b.next;
blen++;
}
207
Intersection of Linked List
208
Flatten Binary Tree to Linked List
Here we use the right pointer in TreeNode as the next pointer in ListNode.
Example
1
\
1 2
/ \ \
2 5 => 3
/ \ \ \
3 4 6 4
\
5
\
6
Note
Don't forget to mark the left child of each node to null. Or you will get Time Limit
Exceeded or Memory Limit Exceeded.
Challenge
Do it in-place without any extra memory.
Think
One pass with iterate each right node.
Get current root's left child( left ) if it is not null.
Put current root's right child ( right ) into the most right leaf position of left
209
Flatten Binary Tree to Linked List
child( left ).
Swap the left in to right position if left is not null.
Solution
210
Palindrome Linked List
Example
Given 1->2->1, return true
Challenge
Could you do it in O(n) time and O(1) space?
Solution
211
Palindrome Linked List
// get half
ListNode runner = head;
ListNode walker = new ListNode(0);
walker.next = head;
while(runner != null && runner.next != null) {
runner = runner.next.next;
walker = walker.next;
}
while(move!=null){
ListNode next = move.next;
move.next = tail;
tail = move;
move = next;
}
// check palindrome
while(head != null&& tail != null) {
if(head.val != tail.val)
return false;
head = head.next;
tail = tail.next;
}
return true;
}
}
212
Palindrome Linked List
213
Reverse List in K-Group
If the number of nodes is not a multiple of k then left-out nodes in the end should
remain as it is.
You may not alter the values in the nodes, only nodes itself may be changed. Only
constant memory is allowed.
Example
Given this linked list: 1->2->3->4->5
Think
Consider the list like following:
214
Reverse List in K-Group
when cnt % k == 0:
Solution
215
Reverse List in K-Group
216
Reverse List in K-Group
217
Copy Random Pointer
Challenge
Could you solve it with O(1) space?
Think
Three pass:
Clone every node and attach it right next of original node,
Copy the random pointer for clone node (the next of origianl node's
random pointer)
Cut down the original and clone one
Solution
218
Copy Random Pointer
return resHead;
}
}
219
Merge K Sorted Linked List
Example
Given lists:
[
2->4->null,
null,
-1->null
],
return -1->2->4->null .
Think
Use a heap to receive element from linked list
Tricky part:
Just entered k node in heap instead of pass all nodes in lists.
When poll out element, it also need to push back the next node of polled
node.
Solution
220
Merge K Sorted Linked List
return dummy.next;
}
}
221
Convert Linked List to Binary Search Tree
Example
2
1->2->3 => / \
1 3
Think
Find the middle point in list
Divide and Conquer to build left child and right child node
Solution
222
Convert Linked List to Binary Search Tree
ListNode m = walker.next;
TreeNode root = new TreeNode(m.val);
ListNode left = dummy.next;
ListNode right = walker.next.next;
walker.next = null;
root.left = sortedListToBST(left);
root.right = sortedListToBST(right);
return root;
}
}
223
Tree
Binary Tree
Tree node contains its value and two children: left and right
class TreeNode{
int val;
TreeNode left, right;
}
Binary Search Tree is similar with the binary tree in structure, but just one special
character -- left child's value always less than root, while the right child has
greater value than root.
Pre-order
In-order
Post-order
Level order
Depth of Tree
Maximum Depth
Minimum Depth
Balanced Tree Check
Sub-tree Check
Find a Node and return the Path from Root to target Node
224
Tree
Trick
Design recursion function with boolean type return
Consider the in-order when meet the Binary Search Tree problem
225
Tree Traversal
Tree Treversal
Pre-order
Example
Given binary tree {1,#,2,3}:
1
\
2
/
3
return [1,2,3].
Solution
226
Tree Traversal
227
Tree Traversal
In-order
Example
Given binary tree {1,#,2,3}:
1
\
2
/
3
return [1,3,2].
Solution
228
Tree Traversal
return res;
}
}
229
Tree Traversal
Post-order
Example
Given binary tree {1,#,2,3}:
1
\
2
/
3
return [3,2,1].
Solution
230
Tree Traversal
return res;
}
}
Level Order
Example
Given binary tree {3,9,20,#,#,15,7},
3
/ \
9 20
/ \
15 7
231
Tree Traversal
[
[3],
[9,20],
[15,7]
]
Solution
232
Tree Traversal
if(cur == 0) {
cur = next;
next = 0;
res.add(new ArrayList<>(row));
row = new ArrayList<>();
}
}
return res;
}
/**
* Use DFS algorithm
* @param root: The root of binary tree.
* @return: Level order a list of lists of integer
*/
public ArrayList<ArrayList<Integer>> levelOrder(TreeNode roo
t) {
// write your code here
ArrayList<ArrayList<Integer>> res = new ArrayList<>();
if(root == null)
return res;
DFSUtil(res, 0, root);
return res;
}
233
Tree Traversal
}
DFSUtil(res, level + 1, cur.left);
DFSUtil(res, level + 1, cur.right);
}
}
234
Invert Tree
Example
1 1
/ \ / \
2 3 => 3 2
/ \
4 4
Challenge
Do it in recursion is acceptable, can you do it without recursion?
Solution
235
Invert Tree
/**
* Non-recursion, it likes tree preorder traversal
* @param root: a TreeNode, the root of the binary tree
* @return: nothing
*/
public void invertBinaryTree(TreeNode root) {
if(root == null)
return;
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while(!stack.isEmpty()){
TreeNode node = stack.pop();
TreeNode tmp = node.left;
node.left = node.right;
node.right = tmp;
if(node.right != null)
stack.push(node.right);
if(node.left != null)
stack.push(node.left);
}
}
}
236
Invert Tree
237
Depth of Tree
Depth of Tree
The maximum depth is the number of nodes along the longest path from the root
node down to the farthest leaf node.
Example
Given a binary tree as follow:
1
/ \
2 3
/ \
4 5
Think
Recursively check the depth
Only if the node is a leaf node we stop recursion and return 0
We compare the recursion results from left branch and right branch to get the
maximum value.
Solution
238
Depth of Tree
The minimum depth is the number of nodes along the shortest path from the root
node down to the nearest leaf node.
Example
Given a binary tree as follow:
/ \
2 3
/ \
4 5
239
Depth of Tree
Think
Recursively check the depth
Only if the node is a leaf node we stop recursion and return 0
If a node just have one child, we should not compare the recursion result!
If a node contains both left and right child, we compare the recursion results
to get the minimum value.
Solution
if(root.left == null)
return minDepth(root.right) + 1;
else if(root.right == null)
return minDepth(root.left) + 1;
else
return Math.min(minDepth(root.left), minDepth(root.r
ight)) + 1;
}
}
240
Balanced Tree
For this problem, a height-balanced binary tree is defined as a binary tree in which
the depth of the two subtrees of every node never differ by more than 1.
Example
Given binary tree A={3,9,20,#,#,15,7}, B={3,#,20,15,7}
A) 3 B) 3
/ \ \
9 20 20
/ \ / \
15 7 15 7
Think
Get two max depths from left branch and right branch
Recursive from bottom to top and Compare two max depth on each node
If the difference between two depth is larger than one, regard it as non-
balanced tree.
Solution
241
Balanced Tree
242
Lowest Common Ancestor
The lowest common ancestor is the node with largest depth which is the ancestor
of both nodes.
Example
For the following binary tree:
4
/ \
3 7
/ \
5 6
LCA(3, 5) = 4
LCA(5, 6) = 7
LCA(6, 7) = 7
Think
Recursively traversal on every tree node
Once it touched null or target A node or target B node, it return it self
Divide and conquer to get return from left branch and right branch
Check if both return result are not null, means current node is the common
ancestor
If it is not, return the not null one or return null if both are null
Solution
243
Lowest Common Ancestor
244
Search Range in Binary Search Tree
Example
If k1 = 10 and k2 = 22, then your function should return [12, 20, 22].
20
/ \
8 22
/ \
4 12
Think
Recursion on each valid node.
For invalid node, if it is less than k1, check its right child, while if it is larger
than k2, check its left child
Add the result from left and itself and right
Solution
245
Search Range in Binary Search Tree
246
Count Univalue Subtree
A Uni-value subtree means all nodes of the subtree have the same value.
For example:
5
/ \
1 5
/ \ \
5 5 5
return 4 .
Think
Typical Tree problem with recursion idea
Four cases in recursion:
Leaf node: if true case and increase the counter
Node with on one child:
Left Only: check return value from left child and value of left child
should be the same as current node.
Right Only: check return value from right child and value of right
child should be the same as current node.
Node with two children: check return value from both side and both child
node value should be the same as current node.
Solution
247
Count Univalue Subtree
248
Count Univalue Subtree
249
Verify Preorder Sequence in BST
Follow up
Could you do it using only constant space complexity?
Think #1
The first element should be the root node.
Find the bound that all previous element are small than root value by
checking the first larger element.
So the left of this bound should be the left tree of root, and the rest of it
should be the right tree of root.
Check left and right recursively.
Time Complexity: , Space Complexity:
Solution #1
250
Verify Preorder Sequence in BST
Think #2
Preorder in BST has a regular pattern:
When going to left node, it must be a descending order
When going to right node, it should be a ascending order
Setting a stack, to store the previous path. Iterate throught the array:
When it getting smaller element make it just push into stack
When it find the larger element (larger than the peek of stack), pop the
stack and set the minimum limit as the value of popped element.
Time Complexity: , Space Complexity:
For Example, 10 5 2 7 6 8 12 11 -> BST
251
Verify Preorder Sequence in BST
10
/ \
5 12
/ \ /
2 7 11
/ \
6 8
Solution #2
Think #3
Optimized on the #2 solution
Use a pointer to replace the stack peek position.
指针模拟栈
252
Verify Preorder Sequence in BST
Solution #3
253
Closest BST Value
Problem I
Given a non-empty binary search tree and a target value, find the value in the
BST that is closest to the target.
Note
Given target value is a floating point. You are guaranteed to have only one unique
value in the BST that is closest to the target.
Solution
254
Closest BST Value
Problem II
Given a non-empty binary search tree and a target value, find k values in the BST
that are closest to the target.
Note
Given target value is a floating point.
255
Closest BST Value
Follow up
Assume that the BST is balanced, could you solve it in less than runtime
(where n = total nodes)?
Hint
Consider implement these two helper functions:
getPredecessor(N) , which returns the next smaller node to N.
getSuccessor(N) , which returns the next larger node to N.
Try to assume that each node has a parent pointer, it makes the problem
much easier.
Without parent pointer we just need to keep track of the path from the root to
the current node using a stack.
You would need two stacks to track the path in finding predecessor and
successor node separately.
Think #1
The straight-forward solution would be to use a heap.
We just treat the BST just as a usual array and do a in-order traverse.
Then we compare the current element with the minimum element in the heap,
the same as top k problem.
Solution #1
class Solution {
private PriorityQueue<Integer> minPQ;
private int count = 0;
public List<Integer> closestKValues(TreeNode root, double ta
rget, int k) {
minPQ = new PriorityQueue<;Integer>(k);
List<Integer> result = new ArrayList<Integer>();
256
Closest BST Value
return result;
}
if (count < k) {
minPQ.offer(root.val);
} else {
if (Math.abs((double) root.val - target) < Math.abs((
double) minPQ.peek() - target)) {
minPQ.poll();
minPQ.offer(root.val);
}
}
count++;
Think #2
Stack solution to replace the recursion way for inorder traversal
Maintain a queue with K size, compare the head of queue and current value
257
Closest BST Value
Solution #2
258
Closest BST Value
if(root.right !=null) {
root = root.right;
}else
root = null;
} while (!stack.isEmpty());
return new ArrayList<Integer>(values);
}
259
Graph
260
Route Between Directed Graph
Think
Most typical Graph algorithm question!
Try two ways: DFS, BFS.
Solution
// BFS
public boolean hasRoute(ArrayList<DirectedGraphNode> graph,
DirectedGraphNode s, DirectedGraphNo
de t) {
if(s == t)
return true;
261
Route Between Directed Graph
if(!graph.contains(next))
continue;
if(next == t)
return true;
queue.offer(next);
}
}
return false;
}
// DFS
public boolean hasRoute(ArrayList<DirectedGraphNode> graph,
DirectedGraphNode s, DirectedGraphNo
de t) {
// write your code here
if(s == t)
return true;
262
Graph Valid Tree
Example
Given n = 5 and edges = [[0, 1], [0, 2], [0, 3], [1, 4]] , return true.
Given n = 5 and edges = [[0, 1], [1, 2], [2, 3], [1, 3], [1, 4]] ,
return false.
Hint
The definition of tree on Wikipedia:
Note: You can assume that no duplicate edges will appear in edges. Since
all edges are undirected, [0, 1] is the same as [1, 0] and thus will not
appear together inedges.
Think
Given n = 5 and edges = [[0, 1], [1, 2], [3, 4]] , what should your
return? Is this case a valid tree?
263
Graph Valid Tree
Solution #BFS
264
Graph Valid Tree
while (!queue.isEmpty()) {
int vertexId = queue.poll();
// touch the cycle
if (visited[vertexId])
return false;
visited[vertexId] = true;
for (int neighbor : nodes[vertexId].neighbors) {
if (!visited[neighbor])
queue.offer(neighbor);
}
}
Solution #DFS
265
Graph Valid Tree
266
Graph Valid Tree
267
Alien Dictionary
Alien Dictionary
There is a new alien language which uses the latin alphabet. However, the order
among letters are unknown to you. You receive a list of words from the dictionary,
where words are sorted lexicographically by the rules of this new language. Derive
the order of letters in this language.
Example
Given the following words in dictionary, [ "wrt", "wrf", "er", "ett",
"rftt" ] The correct order is: "wertf" .
Note
You may assume all letters are in lowercase.
If the order is invalid, return an empty string.
There may be multiple valid order of letters, return any one of them is fine.
Think
Typical topological problem
Solution
268
Alien Dictionary
: new Node(str.charAt(0)));
for (int i = 1; i < str.length(); i++) {
char cur = str.charAt(i);
// ignore the adjacent equal characters
if(cur == str.charAt(i-1))
continue;
Node node = map.containsKey(cur) ? map.get(cur)
: new Node(cur);
Node prev = map.get(str.charAt(i - 1));
// make current node indegree plus one only if t
he previous node doesn't have current node in its neighborhood l
ist
if (!prev.neighbors.contains(node) ) {
node.indegree++;
map.get(str.charAt(i - 1)).neighbors.add(nod
e);
}
map.put(cur, node);
}
}
269
Alien Dictionary
}
// if map has any entry means the cycle existed
if (map.size() > 0)
return "";
return sb.toString();
}
public Node(char c) {
this.c = c;
this.indegree = 0;
this.neighbors = new ArrayList<>();
}
}
270
Segment Tree
271
Segment Tree Build I
The structure of Segment Tree is a binary tree which each node has two attributes
start and end denote an segment / interval.
start and end are both integers, they should be assigned in following rules:
Implement a build method with two parameters start and end, so that we can
create a corresponding segment tree with every node has the correct start and
end value, return the root of this segment tree.
Example
Given start=0, end=3. The segment tree will be:
[0, 3]
/ \
[0, 1] [2, 3]
/ \ / \
[0, 0] [1, 1] [2, 2] [3, 3]
[1, 6]
/ \
[1, 3] [4, 6]
/ \ / \
[1, 2] [3,3] [4, 5] [6,6]
/ \ / \
[1,1] [2,2] [4,4] [5,5]
Clarification
272
Segment Tree Build I
Segment Tree (a.k.a Interval Tree) is an advanced data structure which can
support queries like:
Solution
273
Segment Tree Build I
274
Segment Tree Build II
The structure of Segment Tree is a binary tree which each node has two attributes
start and end denote an segment / interval.
start and end are both integers, they should be assigned in following rules:
Example
Given [3,2,1,4]. The segment tree will be:
[0, 3] (max = 4)
/ \
[0, 1] (max = 3) [2, 3] (max = 4)
/ \ / \
[0, 0](max = 3) [1, 1](max = 2)[2, 2](max = 1) [3, 3] (max = 4)
Clarification
Segment Tree (a.k.a Interval Tree) is an advanced data structure which can
support queries like:
Solution
275
Segment Tree Build II
276
Segment Tree Query I
For an integer array (index from 0 to n-1, where n is the size of this array), in the
corresponding SegmentTree, each node stores an extra attribute max to denote
the maximum number in the interval of the array (index from start to end).
Design a query method with three parameters root, start and end, find the
maximum number in the interval [start, end] by the given root of segment tree.
Example
For array [1, 4, 2, 3], the corresponding Segment Tree is:
[0, 3, max=4]
/ \
[0,1,max=4] [2,3,max=3]
/ \ / \
[0,0,max=1] [1,1,max=4] [2,2,max=2], [3,3,max=3]
query(root, 1, 1) , return 4
query(root, 1, 2) , return 4
query(root, 2, 3) , return 3
query(root, 0, 2) , return 4
Note
It is much easier to understand this problem if you finished Segment Tree Build
first.
Solution:
277
Segment Tree Query I
278
Segment Tree Query II
For an array, we can build a SegmentTree for it, each node stores an extra
attribute count to denote the number of elements in the the array which value is
between interval start and end. (The array may not fully filled by elements)
Design a query method with three parameters root, start and end, find the number
of elements in the in array's interval [start, end] by the given root of value
SegmentTree.
Example
For array [0, 2, 3], the corresponding value Segment Tree is:
[0, 3, count=3]
/ \
[0,1,count=1] [2,3,count=2]
/ \ / \
[0,0,count=1] [1,1,count=0] [2,2,count=1], [3,3,count=1]
query(1, 1) , return 0
query(1, 2) , return 1
query(2, 3) , return 2
query(0, 2) , return 2
Note
It is much easier to understand this problem if you finished Segment Tree
Buildand Segment Tree Query first.
Solution
279
Segment Tree Query II
if(start > m)
return query(root.right, start, end);
else if(end <= m)
return query(root.left, start, end);
else
return query(root.left, start, m) + query(root.right
, m+1, end);
}
}
280
Segment Tree Query II
281
Segment Tree Modify
For a Maximum Segment Tree, which each node has an extra value max to store
the maximum value in this node's interval.
Implement a modify function with three parameter root, index and value to change
the node's value with [start, end] = [index, index] to the new given value. Make
sure after this change, every node in segment tree still has the max attribute with
the correct value.
Example
For segment tree:
[1, 4, max=3]
/ \
[1, 2, max=2] [3, 4, max=3]
/ \ / \
[1, 1, max=2], [2, 2, max=1], [3, 3, max=0], [4, 4, max=3]
[1, 4, max=4]
/ \
[1, 2, max=4] [3, 4, max=3]
/ \ / \
[1, 1, max=2], [2, 2, max=4], [3, 3, max=0], [4, 4, max=3]
[1, 4, max=2]
/ \
[1, 2, max=2] [3, 4, max=0]
/ \ / \
[1, 1, max=2], [2, 2, max=1], [3, 3, max=0], [4, 4, max=0]
Note
282
Segment Tree Modify
We suggest you finish problem Segment Tree Build and Segment Tree Query
first.
Challenge
Do it in O(h) time, h is the height of the segment tree.
Solution:
283
Interval Sum I
Given an integer array (index from 0 to n-1, where n is the size of this array), and
an query list. Each query has two integers [start, end]. For each query, calculate
the sum number between index start and end in the given array, return the result
list.
Example
For array [1,2,7,8,5] , and queries [(0,4),(1,2),(2,4)] , return
[23,9,20]
Challenge
O(logN) time for each query
Solution
public IntervalTree(int[] A) {
root = build(A, 0, A.length - 1);
}
if(start == end) {
node.val = (long)A[start];
return node;
}
284
Interval Sum I
285
Interval Sum I
*/
public ArrayList<Long> intervalSum(int[] A,
ArrayList<Interval> queri
es) {
IntervalTree tree = new IntervalTree(A);
ArrayList<Long> res = new ArrayList<>();
for(Interval interval : queries) {
res.add(tree.query(interval.start, interval.end));
}
return res;
}
}
286
Interval Sum II
For query(start, end), return the sum from index start to index end in the given
array.
For modify(index, value), modify the number in the given index to value.
Example
Given array A = [1,2,7,8,5] .
query(0, 2) , return 10 .
modify(0, 4) , change A[0] from 1 to 4 .
query(0, 1) , return 6 .
modify(2, 1) , change A[2] from 7 to 1 .
query(2, 4) , return 14 .
Challenge
O(logN) time for query and modify.
Solution:
IntervalNode root;
/**
* @param A: An integer array
*/
public Solution(int[] A) {
root = build(A, 0, A.length - 1);
}
287
Interval Sum II
if(start == end) {
node.val = (long)A[start];
return node;
}
/**
* @param start, end: Indices
* @return: The sum from start to end
*/
public long query(int start, int end) {
return query(root, start, end);
}
/**
* @param index, value: modify A[index] to value.
*/
public void modify(int index, int value) {
288
Interval Sum II
289
Interval Minimum Number
Given an integer array (index from 0 to n-1, where n is the size of this array), and
an query list. Each query has two integers [start, end]. For each query, calculate
the minimum number between index start and end in the given array, return the
result list.
Example
For array [1,2,7,8,5] , and queries [(1,2),(0,4),(2,4)] , return
[2,1,5]
Challenge
O(logN) time for each query (Segment Tree)
Solution
/**
* Build Interval Tree with Min of segment!
*
290
Interval Minimum Number
*/
class IntervalTree{
IntervalNode root;
public IntervalTree(int[] A) {
root = build(A, 0, A.length - 1);
}
if(start == end) {
node.min = A[start];
return node;
}
291
Interval Minimum Number
}else
return Math.min(queryhelper(node.left, start, m)
, queryhelper(node.right, m+1, end));
}
292
Count Smaller Number before itself
Example
For array [1,2,7,8,5] , return [0,1,2,3,2]
Think
Segment Tree
Initial with the range (0 to 10000)
Count array elements included in a certain tree node
Dynamic count and make a query.
Query a value, evaluate the value and node's middle value,
if larger, that means the left node's count should be included and also
enter into the right node;
if less, just enter the left node;
recursive until touch the null node;
Solution
class SegmentTree{
Node root;
public SegmentTree(){
root = build(0, 20000);
}
293
Count Smaller Number before itself
if(left == right)
return new Node(left, right);
294
Count Smaller Number before itself
class Node{
int left, right;
long cnt;
Node leftNode, rightNode;
public Node(int left, int right){
this.cnt = 0;
this.left = left;
this.right = right;
}
}
295
Math
296
Integer To Roman
Integer to Roman
Given an integer, convert it to a roman numeral.
Example
4 -> IV
12 -> XII
21 -> XXI
99 -> XCIX
Think
Store special integer value and its corresponding roman value;
Get a loop to minus the integer value from large to small (if n greater than
that integer value), then get index and the corresponding roman value;
Solution:
297
Integer To Roman
298
Roman to Integer
Roman to Integer
Given a roman numeral, convert it to an integer.
Example
IV -> 4
XII -> 12
XXI -> 21
XCIX -> 99
Clarification
Symbol Value
I 1
V 5
X 10
L 50
C 100
D 500
M 1,000
同一数码最多只能出现三次,如40不可表示为XXXX,而要表示为XL。
在较大的罗马数字的右边记上较小的罗马数字,表示大数字加小数字。
在较大的罗马数字的左边记上较小的罗马数字,表示大数字减小数字。
左减的数字有限制,仅限于I、X、C。比如45不可以写成VL,只能是XLV。
但是,左减时不可跨越一个位数。比如,99不可以用IC(100 - 1)表示,是用
XCIX([100 - 10] + [10 - 1])表示。
左减数字必须为一位,比如8写成VIII,而非IIX。
右加数字不可连续超过三位,比如14写成XIV,而非XIIII。(见下方“数码限
299
Roman to Integer
制”一项。)
Solution
int res = 0;
for (int i = 0; i < s.length() ; i++) {
if(i < s.length() - 1 && map.get(s.charAt(i)) < map.
get(s.charAt(i+1)) )
res -= map.get(s.charAt(i));
else
res += map.get(s.charAt(i));
}
return res;
}
}
300
Ugly Number I
Ugly Number I
Write a program to check whether a given number is an ugly number.
Ugly numbers are positive numbers whose prime factors only include 2, 3, 5 .
For example, 6, 8 are ugly while 14 is not ugly since it includes another
prime factor 7 .
Think
Make sure the value can be divided exactly by the divisor in array 2, 3, 5 ;
So iterate the division while the value can be divided exactly, otherwise
change another divisor from array.
Solution
301
Ugly Number II
Ugly Number II
Write a program to find the n-th ugly number.
Ugly numbers are positive numbers whose prime factors only include 2, 3, 5 .
For example, 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 is the sequence of the first
10 ugly numbers.
Think
Declare an array for ugly numbers: ugly[150]
Initialize first ugly no: ugly[1] = 1
Initialize three array index variables t2, t3, t5 to point to 1st element of the
ugly array:
i2 = i3 = i5 = 1;
next_mulitple_of_2 = ugly[i2]*2;
next_mulitple_of_3 = ugly[i3]*3
next_mulitple_of_5 = ugly[i5]*5;
Choose the minimum from the aboved 3 choices as the next ugly number.
Check which choice and increase that index.
Solution
302
Ugly Number II
303
Fast Power
Fast Power
Calculate the where a, b and n are all 32bit integers.
Example:
For 231 % 3 = 2 For 1001000 % 1000 = 0
Challenge:
O(logn)
Think
Divide and Conquer
Think about the two basic condition: n is 1 and n is 0;
Each time we divide the n into two part (n/2);
Then we got the combine value (divide * divide) from both parts (they're
eqaul, actually);
While n is odd, we need to add one more "a" time (*a);
Solution
304
Fast Power
class Solution {
/*
* @param a, b, n: 32bit integers
* @return: An integer
*/
public int fastPower(int a, int b, int n) {
if(n == 1)
return a % b;
if(n == 0)
return 1 % b;
305
Square Root
Sqrt(x)
Implement int sqrt(int x) .
Note
Try to make the time complexity less.
Think
The square root should be between 1 to half of input value;
Use binary search idea to search the sqrt inside that range;
Solution
306
Square Root
307
Binary Representation
Binary Representation
Given a (decimal - e.g. 3.72) number that is passed in as a string, return the
binary representation that is passed in as a string. If the fractional part of the
number can not be represented accurately in binary with at most 32 characters,
return ERROR .
Example
For n = "3.72" , return "ERROR" .
Think
For Integer part, we use % 2 to get each digit from lowest bit to highest bit,
or use a loop to make & with 1 and left shift until it get zero.
For decimal part, we can use approach. For example: int n = 0.75;
n*2 = 1.5; Therefore, the first digit of binary number after . is 1 (i.e.
0.1). After constructed the first digit, n= n*2-1;
Solution
308
Binary Representation
while(intPart != 0) {
res.insert(0, "" + (intPart & 1));
intPart >>= 1;
}
if(res.length() == 0)
res.append(0);
double decPart = Double.parseDouble(n.substring(n.indexO
f('.')));
String decBit = "";
// if it has decimal part, creat '.' in result string
if(decPart > 0.0)
res.append(".");
// to count how many digit in decimal binary result
int cnt = 0;
while(decPart > 0.0) {
double cur = (decPart * 2);
cnt++;
if(cnt > 32)
return "ERROR";
if(cur >= 1) {
res.append(1);
decPart = cur - 1.0;
}else {
res.append(0);
decPart = cur;
}
}
return res.toString();
}
}
309
Divide Two Integers
Example
Given dividend = 100 and divisor = 9 , return 11 .
Think
Bitwise Idea:
Get the result sign (negative or positive) by ((dividend ^ divisor)
>>> 31) == 1
This question contains many corner cases!
Firstly, check the corner cases in following steps:
Divisor is zero? return Integer.MAX_VALUE ;
Dividend is Integer.MIN_VALUE ?
if divisor is negative one? you cannot get the positive
MIN_VALUE so return Integer.MAX_VALUE ;
dividend += Math.abs(divisor) so that the dividend
become away from overflow but that leads the res increase one;
Divisor is Integer.MIN_VALUE ? return res; To avoid the
inaccurate from above operation;
Make dividend and divisor both positive;
Then, the main operation to do the binary substraction;
Get the most higher position( digit ) for bit one with increasing the
divisor until it is just larger than ( dividend >> 1 ): divisor cannot
larger than dividend so that we use the dividend>>1
Get result by add the 1<<digit (current bit position should be
one) and dividend -= divisor but if divisor larger than dividend
which means current bit position should be zero so just reduce digit
and divisor should shift right one position each time;
310
Divide Two Integers
Solution
if(divisor == Integer.MIN_VALUE)
return res;
while(digit>=0){
if(dividend>=divisor){
res += (1<<digit);
dividend-=divisor;
}
311
Divide Two Integers
divisor>>=1;
digit--;
}
return neg?-res:res;
}
}
312
Digit Counts
Digit Counts
Count the number of k's between 0 and n. k can be 0 - 9.
Example
if n=12, k=1 in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] , we have
FIVE 1's (1, 10, 11, 12)
Think #1
Brute Force: Check each digit in number form (0 -> n) then get the count;
Solution #1
Think #2
Math:
When current digit less than k , the current count should be higher
digits x digit position (pos x 10) ;
313
Digit Counts
Solution #2
class Solution {
/*
* param k : As description.
* param n : As description.
* return: An integer denote the count of digit k in 1..n
*/
public int digitCounts(int k, int n) {
int digit = 1;
int cnt = 0;
while(digit <= n) {
int low = n % digit; // lower digits;
int high = n / (digit*10); // higher digits;
int cur = n / digit % 10;
if(cur == k) {
// higher digits * digit + lower digits + 1;
cnt += ((high * digit) + low + 1);
}else if(cur < k) {
// higher digits * digit
cnt += (high * digit);
}else{
// (higher digits + 1: itself) * digit
cnt += ((high + (k == 0?0:1)) * digit);
}
digit *= 10;
}
return cnt + (k == 0 ? 1 : 0);
}
};
314
Digit Counts
315
Expression
316
Reverse Polish Notation (RPN)
Example
Think
Reverse Polish Notation problems always accompany with the stack as its
data structure;
Setup stack only to store the integer value;
One pass the tokens array, when get the integer, insert the stack, while get
the operator, to do the evaluate with pop two value from stack and push back
the result after calculated;
Its good to use switch rather than if ;
Solution
317
Reverse Polish Notation (RPN)
switch(str){
case "+":
curRes = (stack.isEmpty()?0:stack.pop()) + (
stack.isEmpty()?0:stack.pop());
break;
case "-":
curRes = stack.isEmpty()?0:stack.pop();
curRes = (stack.isEmpty()?0:stack.pop()) - c
urRes;
break;
case "*":
curRes = (stack.isEmpty()?0:stack.pop()) *
(stack.isEmpty()?0:stack.pop());
break;
case "/":
curRes = stack.isEmpty()?0:stack.pop();
if(curRes == 0)
break;
curRes = (stack.isEmpty()?0:stack.pop()) / c
urRes;
break;
default:
curRes = Integer.parseInt(str);
}
stack.push(curRes);
}
return stack.isEmpty()?0:stack.pop();
}
}
318
Convert Expression to RPN
Example
For the expression [3 - 4 + 5] (which denote by ["3", "-", "4", "+",
"5"] ), return [3 4 - 5 +] (which denote by ["3", "4", "-", "5", "+"] )
Think
Always consider stack firstly, when meet a reverse polish notation problem.
The operator priority ( * , / ) > ( + , - ), when get the operator is less
priority than stack top element, pop the stack util the element has the same
priority as the current operator and output the pop element in result list.
Push the "(" always but pop the stack when get the ")" until stack has pop the
corresponding "(".
When get the operand, just output in result list.
Solution
319
Convert Expression to RPN
320
Convert Expression to RPN
321
Convert Expression to PN
Polish notation, also known as Polish prefix notation or simply prefix notation,
is a form of notation for logic, arithmetic, and algebra. Its distinguishing
feature is that it places operators to the left of their operands. If the arity of the
operators is fixed, the result is a syntax lacking parentheses or other brackets
that can still be parsed without ambiguity. The Polish logician Jan Łukasiewicz
invented this notation in 1924 in order to simplify sentential logic.
Example
For the expression [(5 − 6) * 7] (which represented by ["(", "5", "−",
"6", ")", "*", "7"] ), the corresponding polish notation is [* - 5 6 7]
(which the return value should be ["*", "−", "5", "6", "7"] ).
Think
The idea is not complext if you took the reverse polish notation question.
Just two things changed:
Pass from rear to head;
Every insertion is to the first index in result list
Solution
322
Convert Expression to PN
323
Calculator
Example
For the expression 2*6-(23+7)/(1+2) , input is
[
"2", "*", "6", "-", "(",
"23", "+", "7", ")", "/",
(", "1", "+", "2", ")"
],
return 2
Note
The expression contains only integer , + , - , * , / , ( , ) .
Think
This question is combination of read string array to RPN and then read RPN
to get the integer result.
So.... two steps:
first, build RPN
second, read the RPN
Solution
324
Calculator
* @return: an integer
*/
public int evaluateExpression(String[] expression) {
// two steps:
// first, build RPN
ArrayList<String> list = convertToRPN(expression);
// second, read the RPN
return RPNreader(list);
}
325
Calculator
else
return 0;
}
return stack.isEmpty()?0:stack.pop();
}
};
326
Calculator
327
Expression Tree Build
Now, given an expression array, build the expression tree of this expression,
return the root of this expression tree.
Example
For the expression (2*6-(23+7)/(1+2)) (which can be represented by ["2"
"*" "6" "-" "(" "23" "+" "7" ")" "/" "(" "1" "+" "2" ")"] ). The
expression tree will be like
[ - ]
/ \
[ * ] [ / ]
/ \ / \
[ 2 ] [ 6 ] [ + ] [ + ]
/ \ / \
[ 23 ][ 7 ] [ 1 ] [ 2 ] .
After building the tree, you just need to return root node [-] .
Clarification
A binary expression tree is a specific application of a binary tree to evaluate
certain expressions. Two common types of expressions that a binary expression
tree can represent are algebraic[1] and boolean. These trees can represent
expressions that contain both unary and binary operators.
328
Expression Tree Build
class ExpressionTreeNode {
public String symbol;
public ExpressionTreeNode left, right;
public ExpressionTreeNode(String symbol) {
this.symbol = symbol;
this.left = this.right = null;
}
}
Think
Two stacks, one is only for operator, another is for build the result tree.
The idea is similar with RPN.
One pass the expression array, when it get a operand, insert as new treenode
in result tree, when it get a operator, insert as new treenode in operator tree
and compare the priority, if the current is less than stack top element, build a
new node with operator in stack top and two node from result tree as its right
and left child, then insert back to result tree with this new node.
Solution
329
Expression Tree Build
}
ops.push(new ExpressionTreeNode(str));
}else if(str.equals("(")){
ops.push(new ExpressionTreeNode(str));
}else if(str.equals(")")) {
while(!ops.isEmpty() && !ops.peek().symbol.equal
s("("))
newNodeGtr(ops, data);
if(!ops.isEmpty())
ops.pop(); // pop the "("
}else
data.push(new ExpressionTreeNode(str));
}
while(!ops.isEmpty())
newNodeGtr(ops, data);
330
Expression Tree Build
331
Bit Manipulation
332
Update Bits
Update Bits
Given two 32-bit numbers, N and M, and two bit positions, i and j. Write a method
to set all bits between i and j in N equal to M (e g , M becomes a substring of N
located at i and starting at j).
Example
Given N= (10000000000)2 , M= (10101)2 , i= 2 , j= 6 return
N= (10001010100)2
Note
In the function, the numbers N and M will given in decimal, you should also return
a decimal number.
Challenge
Minimum number of operations?
Clarification
You can assume that the bits j through i have enough space to fit all of M. That is,
if M = 10011 , you can assume that there are at least 5 bits between j and i. You
would not, for example, have j=3 and i=2, because M could not fully fit between bit
3 and bit 2.
Think
Set a mask:
333
Update Bits
Use that mask to do & with N, so that in the new N, the position i~j will be
zero.
Solution
class Solution {
/**
*@param n, m: Two integer
*@param i, j: Two bit positions
*return: An integer
*/
public int updateBits(int n, int m, int i, int j) {
int mask = 0;
for(int lfShift = 31; lfShift > j; lfShift--)
mask += (1<<lfShift);
334
Data Structure
Data Structure
People build so many data structure only for one purpose - easy to manipulate.
Those structure is supporting the computer science, just like how we place the
goods in warehouse. Here is how we place the data.
Array
It is the most basic structure. But the most easy things can be the most
sophisticate, like traditional Chinese philosophy, like DNA build all creature in the
world.
More Structural
Binary Tree
Heap
Stack
Queue
335
Data Structure
Disjoint Set
Graph
336
Map
Map
Overview
There are 4 commonly used implementations of Map in Java SE - HashMap,
TreeMap, Hashtable and LinkedHashMap. If we use only one sentence to
describe each implementation, it would be the following:
Note that the HashSet doesn't implement Map interface but it is based on
HashMap. It contains HashMap insided as the value storage.
337
Map
The Java super class java.lang.Object has two very important methods defined:
Once you override the equal() function, you must be careful to treat the
hashCode() function. The contract between equals() and hashCode() is
that:
1. If two objects are equal, then they must have the same hash code.
2. If two objects have the same hashcode, they may or may not be equal.
Hash Collision
Closed hashing:
Linear Probing, Quadratic Probing, Double hashing(Constant prime as the next
hash size( x - val%x));
Open hashing:
Chaining Address. key-value pairs are stored in linked lists attached to cells of a
hash table.
338
Map
Step 1: By having each bucket contain a linked list of elements that are hashed to
that bucket. This is why a bad hash function can make look-ups in hash tables
very slow. Because the bad hash function make the items location less disperse
and lead to some clusters.
Step 2: What if the nodes in HashMap are almost fulled? Two concept need to be
introdued firstly:
Threshold
Load Factor
Threshold is a value when the number of entry nodes in HashMap touch this
value, the resize() function should be triggered. Threshold value should be
evaluated by the loadFactor which is set 0.75 as its default value.That
means .
Step 3: Resize and rehash. The hash function returns an integer and the hash
table has to take the result of the hash function and mod it against the size of the
table that way it can be sure it will get to bucket. so by increasing the size it will
rehash and run the modulo calculations which if you are lucky might send the
objects to different buckets.
339
Hash Map
HashMap
340
Hash Map
/**
* The table, initialized on first use, and resized as
* necessary. When allocated, length is always a power of
two.
* (We also tolerate length zero in some operations to all
ow
* bootstrapping mechanics that are currently not needed.)
*/
transient Node<K,V>[] table;
However, HashMap provides three views for retrieving the inside data:
keySet() , values() and entrySet()
341
Hash Map
/**
* NOTE! This field is in AbstractMap class
* Each of these fields are initialized to contain an inst
ance of the
* appropriate view the first time this view is requested.
The views are
* stateless, so there's no reason to create more than one
of each.
*/
transient volatile Set<K> keySet;
/**
* NOTE! This field is in AbstractMap class
*/
transient volatile Collection<V> values;
/**
* This field is in HashMap class
* Holds cached entrySet(). Note that AbstractMap fields a
re used
* for keySet() and values().
*/
transient Set<Map.Entry<K,V>> entrySet;
Insertion
342
Hash Map
/**
* @return the previous value associated with key, or
* null if there was no mapping for key.
* (A null return can also indicate that the map
* previously associated null with key.)
*/
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
/**
* The original version about put k-v pair node implement.
* Notice those two boolean value
* @param hash hash for key
* @param key the key
* @param value the value to put
* @param onlyIfAbsent if true, don't change existing value
* @param evict if false, the table is in creation mode.
* @return previous value, or null if none
*/
final V putVal(int hash, K key, V value, boolean onlyIfAbsen
t,
boolean evict){...}
343
Hash Map
Insert the new node and update the previous node next pointer: prev.next
= new Node(hash, key, value, null) .
/**
* Lite Editon for HashMap input K - V pair function
**/
final V putVal(int hash, K key, V value) {
// the reference for node table
Node<K,V>[] tab;
// the reference for node in current bucket
Node<K,V> prev;
int n; // the table length
344
Hash Map
prev = exist;
}
}
if (exist != null) { // existing mapping for key
V oldValue = exist.value;
if (oldValue == null)
exist.value = value;
return oldValue;
}
}
// modification count for fail-fast
++modCount;
// check current node amount, if larger than threshodl do re
size
if (++size > threshold)
resize();
return null;
}
Retrieve
The public entrance get(key) returns the value to which the specified key
is mapped, or null if this map contains no mapping for the key. More
formally, if this map contains a K - V pair key==null then this method
returns v or null . Pleas note that return null doesn't necessarily
indicates the map contains no mapping for the key! It's also possible that
the map explicitly maps the key to NULL . Source code shown as below:
345
Hash Map
Check the first node in target bucket if it is the same as the input key and
hash code
Check the rest nodes iterative in target bucket if it matches the retrieval
condition.
Deletion
Removes the mapping for the specified key from this map if present. Return
the previous value associated with input key or null if there was no
mapping for input key (A null return can also indicate that the map
previously associated null key).
346
Hash Map
/**
* The original version about remove node implement.
* Notice those two boolean value
* @param hash hash for key
* @param key the key
* @param value the value to match if matchValue, else ignor
ed
* @param matchValue if true only remove if value is equal
* @param movable if false do not move other nodes while rem
oving
* @return the node, or null if none
*/
final Node<K,V> removeNode(int hash, Object key, Object valu
e,
boolean matchValue, boolean movab
le) {...}
347
Hash Map
if (node != null ) {
if (node == p)
tab[index] = node.next;
else
p.next = node.next;
++modCount;
--size;
return node;
}
}
return null;
}
348
Hash Map
349
Iterator
Iterator
Iterator enables you to cycle through a collection, obtaining or removing elements.
List Iterator extends Iterator to allow bidirectional traversal of a list, and the
modification of elements.
Before you can access a collection through an iterator, you must obtain one. Each
of the collection classes provides an iterator() method that returns an iterator
to the start of the collection. By using this iterator object, you can access each
element in the collection, one element at a time.
350
Iterator
351
Iterator for Two Dimension Array
...
public static void main(String[] args) {
int[][] listOfLists = {
{},{},{1,2,3},{},{},{2,3,4}
};
DeepIterator it = new DeepIterator(listOfLists);
while(it.hasNext()){
System.out.println(it.next());
}
}
}
Think
Iterate the 2-D array by x and y .
Record current element during hasNext() function.
Check the row if it is null.
Solution
352
Iterator for Two Dimension Array
int[][] listOfLists;
353
Iterator for Two Dimension Array
354
Iterator of Iterators
Iterator of Iterators
Given a Iterator which contain several iterator inside. The task is to iterate all
elements inside these iterators. According to the following code, try to build up the
entire class.
Think
It's a class implements iterator interface but also contains several iterators.
Image these iterator is a bucket, the unit is a iterator and the cursor of bucket
index is a iterator element.
Set a current index to point at a iterator.
Solution
355
Iterator of Iterators
@Override
public T next(){
return current.next();
}
@Override
public boolean hasNext(){
if(!current.hasNext())
current = findNext();
return current != null && current.hasNext();
}
@Override
public void remove(){
if(current!=null)
current.remove();
}
}
356
Iterator of Iterators
357
Peek Iterator
Peeking Iterator
Given an Iterator class interface with methods: next() and hasNext() ,
design and implement a PeekingIterator that support the peek() operation -- it
essentially peek() at the element that will be returned by the next call to
next() .
Here is an example. Assume that the iterator is initialized to the beginning of the
list: [1, 2, 3] .
Now you call peek() and it returns 2, the next element. Calling next() after
that still return 2.
You call next() the final time and it returns 3, the last element. Calling
hasNext() after that should return false.
Solution
358
Peek Iterator
int cur;
Iterator<Integer> it;
public PeekingIterator(Iterator<Integer> iterator) {
this.it = iterator;
cur = it.hasNext() ? it.next() : null;
}
@Override
public boolean hasNext() {
return it.hasNext();
}
}
359
Even Iterator
Even Iterator
Implements an iterator only output the even number.
Example
Output
4
6
2
Solution
360
Even Iterator
Iterator<Integer> iterator;
@Override
public boolean hasNext() {
return iterator.hasNext();
}
@Override
public Integer next() {
int res = 0;
while (iterator.hasNext() && (res = iterator.next()) % 2
!= 0)
;
return res;
}
361
Jump Iterator
Jump Iterator
Implements an iterator in each output it print the number and skip the next one.
Partial Code
Output
1
3
6
2
Solution
362
Jump Iterator
Iterator<Integer> iterator;
@Override
public boolean hasNext() {
return iterator.hasNext();
}
@Override
public Integer next() {
int res = iterator.next();
if (iterator.hasNext())
iterator.next();
return res;
}
363
Object Oriented Programming
Principles
Open - Close
Open for extension but closed for modifications
The design and writing of the code should be done in a way that new
functionality should be added with minimum changes in the existing code. The
design should be done in a way to allow the adding of new functionality as
new classes, keeping as much as possible existing code unchanged.
Example
364
Object Oriented Programming
class ShapeEditor{
void drawShape(Shape s){
if (s.m_type==1)
drawRectangle(s);
else if (s.m_type==2)
drawCircle(s);
};
void drawRectangle(Shape s);
void drawCircle(Shape s);
}
class Shape{}
class Rectangle extends Shape{}
class Circle extends Shape{}
Dependency Inversion
The low level classes the classes which implement basic and primary
operations(disk access, network protocols,...) and high level classes the classes
which encapsulate complex logic(business flows, ...). The last ones rely on the low
level classes.
365
Object Oriented Programming
When this principle is applied it means the high level classes are not working
directly with low level classes, they are using interfaces as an abstract layer.
Example
class WorkerWithTechOne{}
class Manager{
WorkerWithTechOne worker;
}
// --> what if add other workers with other techniques?
// --> abstract worker!
interface Worker{}
class WorkerWithTechOne implements Worker{}
class WorkerWithTechTwo implements Worker{}
class Manager{
Worker worker;
}
Interface Segregation
Clients should not be forced to depend upon interfaces that they don't use.
Instead of one fat interface, many small interfaces are preferred based on
groups of methods, each one serving one submodule.
Example
366
Object Oriented Programming
interface work{
public void work();
// too much methods!
public void life();
public void rest();
}
// ---> change!!!
interface work{public void work();}
interface life{public void life();}
interface rest{public void rest();}
Single Responsibility
A class should have only one reason to change.
A simple and intuitive principle, but in practice it is sometimes hard to get it right.
This principle states that if we have 2 reasons to change for a class, we have to
split the functionality in two classes. Each class will handle only one responsibility
and on future if we need to make one change we are going to make it in the class
which handle it. When we need to make a change in a class having more
responsibilities the change might affect the other functionality of the classes.
Example
367
Object Oriented Programming
interface Iemail{
public void setSender(String sender);
public void setReceiver(String receiver);
public void setContent(String content);
// --> change!!!
public void setContent(Content content);
}
// --> Content can be change to HTML or JSON or other kinds of f
ormat
// so it should be splited
interface Content {
public String getAsString(); // used for serialization
}
class email implement Iemail{
public void setSender(String sender) { set sender; }
public void setReceiver(String receiver) { set receiver; }
public void setContent(String content) {set content; }
// --> change!!!
public void setContent(Content content) { set content; }
}
Liskov's Substitution
Derived types must be completely substitutable for their base types.
This principle is just an extension of the Open Close Principle and it means that
we must make sure that new derived classes are extending the base classes
without changing their behavior.
This principle considers what kind of derived class should extends a base class.
Example
368
Object Oriented Programming
Muddiest Points
Example 1:
369
Object Oriented Programming
A Text Editor owns a Buffer (composition). A Text Editor uses a File (aggregation).
When the Text Editor is closed, the Buffer is destroyed but the File itself is not
destroyed.
Interface
Characters
Guide
When you think that the API will not change for a while.
When you want to have something similar to multiple inheritance.
Enforce developer to implement the methods defined in interface.
Interface are used to represent adjective or behavior
Abstract Class
Characters
Guide
370
Object Oriented Programming
All in all
Interface and abstract class can work together also where defining function in
interface and default functionality on abstract class. It also called Skeletal
Implementations.
Reference
1. OO Design Website: oodesign.com
371
Design Pattern
Design Patterns
Creational Patterns
Object Pool Pattern
Prototype Pattern
Factory Method Pattern
Builder Pattern
Factory Pattern
Abstract Factory Pattern
Singleton Pattern
Behavioral Patterns
Memento Pattern
Mediator Pattern
Observer Pattern
Null Object Pattern
Visitor Pattern
Interpreter Pattern
Iterator Pattern
Strategy Pattern
Command Pattern
Template Method Pattern
Chain of Responsibility Pattern
Structural Patterns
Adapter Pattern
Bridge Pattern
Decorator Pattern
Proxy Pattern
Composite Pattern
372
Design Pattern
Flyweight Pattern
373
Practice
374
Deck Card
Deck of Card
Design the data structure for a generic deck of cards. How you would subclass it
to implement particular card games?
Think
Card has suit and value; Suit has four kinds with Club, Spade, Heart and
Diamond.
Solution
375
Deck Card
class Card {
// Define the Suit by Enum type
public enum Suit {
CLUBS(1), SPADE(2), HEART(3), DIAMOND(4);
int value;
private Suit(int val) {
this.value = val;
}
}
// Card has suit and value, only two kind of data need to st
ore
int val;
Suit suit;
BlackJack
Face cards (kings, queens, and jacks) are counted as ten points.
Ace can be counted as 1 point or 11 points
Other cards with value less than ten should be counted as what it values.
376
Deck Card
@Override
public int getVal(){
int value = super.getVal();
if(value < 10)
return value;
else if(value == 1)
return 11;
return 10;
}
377
Chess Game
Chess Game
Some Rules:
Player chooses piece to move through the board.
Piece makes legal move according to its own move rules.
.
If player captures a piece, remove the piece.
If the piece is a pawn reaching the back rank, promote it.
If the move is a castling, set the new position of the rook accordingly. But a
king and rook can only castle if they haven't moved, so you need to keep
track of that. And if the king moves through a check to castle, that's
disallowed, too.
If the move results in a stalemate or checkmate, the game is over.
Hold Pieces
Piece (Abstract):
378
Chess Game
Player (Abstract):
Piece
Destination x, y
public Game() {
board = new Board();
}
board.initialize(p);
return true;
}
379
Chess Game
// System input
do{
Command cmd = new Command(input);
p.addCommand(cmd);
}while(!board.executeMove(p));
}
public startGame(){
// player enter the game:
enterPlayer(new ComputerPlayer("Computer"));
enterPlayer(new HumanPlayer("Bill"));
while(true) {
processTurn(p1);
if(this.board.getWin()) {
System.out.println("P1 win!");
break;
}
processTurn(p2);
if(this.board.getWin()) {
System.out.println("P2 win!");
break;
}
}
}
}
Board:
public Board(){
win = false;
spots = new Spot[8][8];
}
380
Chess Game
381
Chess Game
Spot:
382
Chess Game
return this.piece;
}
}
Pieces:
383
Chess Game
Player:
384
Chess Game
if(this.color == 1){
for(int i=0; i<8; i++){ // draw pawns
pieces.add(new Pawn(true,i,2, 1));
}
pieces.add(new Rook(true, 0, 0, 1));
pieces.add(new Rook(true, 7, 0, 1));
pieces.add(new Bishop(true, 2, 0, 1));
pieces.add(new Bishop(true, 5, 0, 1));
pieces.add(new Knight(true, 1, 0, 1));
pieces.add(new Knight(true, 6, 0, 1));
pieces.add(new Queen(true, 3, 0, 1));
pieces.add(new King(true, 4, 0, 1));
}
else{
for(int i=0; i<8; i++){ // draw pawns
pieces.add(new Pawn(true,i,6, 0));
}
pieces.add(new Rook(true, 0, 7, 0));
pieces.add(new Rook(true, 7, 7, 0));
pieces.add(new Bishop(true, 2, 7, 0));
pieces.add(new Bishop(true, 5, 7, 0));
pieces.add(new Knight(true, 1, 7, 0));
pieces.add(new Knight(true, 6, 7, 0));
pieces.add(new Queen(true, 3, 7, 0));
pieces.add(new King(true, 4, 7, 0));
}
}
}
Command
385
Chess Game
386
Online Reader
Introduction
This question comes from the book named "Cracking Code Interview", Chapter 7;
It is very easy problem with thinking about the insert/remove/update/retrieve
action.
Functionality
User Membership Creation and Extension
Search the book in memory
Reading the book
Analysis
Objects
Book:
ID
Title
Author
Content
Method
showContent
Books: (In-memory storage for many book objects)
Set
Method
find
add
delete
update
387
Online Reader
User
ID
Name
accoutnType
Method
findBook
read (book.showContent)
Users
Set
Method
find
add
delete
update
388
Parking Lot
Parking Lot
Basic Object
Vehicle
size of vehicle (small, medium, large)
status of vehicle (run or parked)
Sedan, SUV, Bus, Truck... extends Vehicle
Slot
size of slot
status (available or not)
Lot
Diagram
Solution
Vehicle
389
Parking Lot
Slot slot;
switch (this.size) {
case 1:
slot = lot.getSmallSlots().remove(0);
case 2:
slot = lot.getCompactSlots().remove(0);
case 3:
slot = lot.getLargeSlots().remove(0);
default:
slot = null;
}
return slot;
}
390
Parking Lot
Lot
391
Parking Lot
private Lot() {
smallSlots = new LinkedList<>();
compactSlots = new LinkedList<>();
largeSlots = new LinkedList<>();
occupiedSlots = new HashMap<>();
for (int i = 1; i <= NUMBER_OF_SMALL_SLOTS; i++)
smallSlots.add(new Slot(i, 1));
Slot
392
Parking Lot
393
Vending Machine
Vending Machine
Idea
The key point for this question is that you should recognize the states switching
process. Essentially, it's a thinking about state pattern.
394
Vending Machine
// 已投币
private final static int HAS_MONEY = 0;
// 未投币
private final static int NO_MONEY = 1;
// 售出商品
private final static int SOLD = 2;
// 商品售罄
private final static int SOLD_OUT = 3;
BUT it'd be better to use classes with designed inheritance relationship, like
following
// 已投币
State coninInsertedState = new CoinInsertedState(this);
// 商品售罄
State emptyState = new EmptyState(this);
// 未投币
State noCoinInsertedState = new NoCoinInsertedState(this);
// 售出商品
State dispensingState = new DispensingState(this);
Code
First We should think about state interface:
State.java
// State interface
import statepattern.exception.MachineWarning;
public interface State {
395
Vending Machine
ConinInsertedState.java
}
public void pressButton() throws MachineWarning{
machine.setMachineState(machine.getDispensingState());
}
}
DispensingState.java
396
Vending Machine
// Dispensing Merchandise
package statepattern;
import statepattern.exception.MachineWarning;
public class DispensingState implements State{
VendingMachine machine ;
DispensingState(VendingMachine machine) {
this.machine = machine;
}
public void insertCoin() throws MachineWarning {
throw new MachineWarning("wait ... previous order is pro
cessing");
}
public void pressButton() throws MachineWarning {
throw new MachineWarning("wait ... previous order is pro
cessing");
}
public void dispense() throws MachineWarning {
machine.setMachineState(machine.getNoCoinInsertedState()
);
}
}
EmptyState.java
397
Vending Machine
NoCoinInsertedState.java
398
Vending Machine
// No coin inserted
package statepattern;
import statepattern.exception.MachineWarning;
public class NoCoinInsertedState implements State{
VendingMachine machine;
public NoCoinInsertedState(VendingMachine machine) {
this.machine = machine;
}
public void insertCoin() throws MachineWarning{
if (!machine.isEmpty()) {
machine.setMachineState(machine.getConinInsertedStat
e());
}
else {
throw new MachineWarning("Can not process request ..
Machine is out of stock");
}
}
public void pressButton() throws MachineWarning{
throw new MachineWarning("No coin inserted ..");
}
public void dispense() throws MachineWarning{
throw new MachineWarning("Invalid Operation");
}
}
VendingMachine.java
package statepattern;
import statepattern.exception.MachineWarning;
public class VendingMachine {
// declare
State coninInsertedState = new CoinInsertedState(this);
State emptyState = new EmptyState(this);
State noCoinInsertedState = new NoCoinInsertedState(this);
State dispensingState = new DispensingState(this);
399
Vending Machine
400
Vending Machine
}
public State getConinInsertedState() {
return coninInsertedState;
}
public void setEmptyState(State emptyState) {
this.emptyState = emptyState;
}
public State getEmptyState() {
return emptyState;
}
public void setNoCoinInsertedState(State noCoinInsertedState)
{
this.noCoinInsertedState = noCoinInsertedState;
}
public State getNoCoinInsertedState() {
return noCoinInsertedState;
}
public void setDispensingState(State dispensingState) {
this.dispensingState = dispensingState;
}
public State getDispensingState() {
return dispensingState;
}
public void setCapacity(int capacity) {
this.capacity = capacity;
}
public int getCapacity() {
return capacity;
}
}
401
System Design
System Design
System design is a wide topic. Even a experienced software engineer at top IT
company may not be an expert on system design. Many books, articles, and solve
real large scale system design problems may needed.
Steps (S - N - A - K - E)
Scenario: (Case/Interface)
Necessary: (Contain/Hypothesis)
Application: (Services/Algorithms)
Kilobyte: (Data)
Evolution
Scenario
Enumerate All possible cases
Register / Login
Main Function One
Main Function Two
...
Sort Requirement
Think about requirement and priority
Necessary
Ask:
User Number
Active Users
Predict
User
402
System Design
Concurrent User:
Peak User:
: c is a constant
Future Expand:
Users growing: max user amount in 3 months
Traffic
Traffic per user (bps)
MAX peak traffic
Memory (< 1 TB is acceptable)
Memory per user
MAX daily memory
Storage
Type of files (e.g movie, music need to store multiple qualities)
Amount of files
Application
Replay the case, add a service for each request
Merge the services
Kilobyte
Append dataset for each request below a service
Choose storage types
Evolution
Analyze
with
Better: constrains
Broader: new cases
Deeper: details
from the views of
Performance
403
System Design
Scalability
Robustness
404
Distributed System Knowledge
Distributed System
Principles
Availability
Performance
Reliability
Scalability
Manageability
Cost-Effective
How to distributed?
405
Distributed System Knowledge
The distributed system is also combined with those three parts.To design a
system with distributed thinking can easier to extend based on the original Von
Neumann structure.
Controller
Controlled the action and behavior between nodes in entire distributed system.
Make nodes in system work collaboratively. There are several ways to achieve
this point:
Hardware
F5
Software
Transparent proxy: Both sides don't know each others. Only rely on the middle
proxy. Cause two problems:1) Traffic overload; 2) The horrible situation when
proxy machine is down;
Naming Service
Rule Server
Master-Workers
调度器通过"轮叫"调度算法将外部请求按顺序轮流分配到集群中的真实服务器
上,它均等地对待每一台服务器,而不管服务器上实际的连接数和系统负载。
调度器通过"加权轮叫"调度算法根据真实服务器的不同处理能力来调度访问请
求。这样可以保证处理能力强的服务器处理更多的访问流量。调度器可以自动
问询真实服务器的负载情况,并动态地调整其权值。
406
Distributed System Knowledge
Least Connections
调度器通过"最少连接"调度算法动态地将网络请求调度到已建立的链接数最少
的服务器上。如果集群系统的真实服务器具有相近的系统性能,采用"最小连
接"调度算法可以较好地均衡负载。
在集群系统中的服务器性能差异较大的情况下,调度器采用"加权最少链接"调
度算法优化负载均衡性能,具有较高权值的服务器将承受较大比例的活动连接
负载。调度器可以自动问询真实服务器的负载情况,并动态地调整其权值。
"基于局部性的最少链接" 调度算法是针对目标IP地址的负载均衡,目前主要用
于Cache集群系统。该算法根据请求的目标IP地址找出该目标IP地址最近使用
的服务器,若该服务器 是可用的且没有超载,将请求发送到该服务器;若服务
器不存在,或者该服务器超载且有服务器处于一半的工作负载,则用"最少链
接"的原则选出一个可用的服务 器,将请求发送到该服务器。
"带复制的基于局部性最少链接"调度算法也是针对目标IP地址的负载均衡,目
前主要用于Cache集群系统。它与LBLC算法的不同之处是它要维护从一个 目
标IP地址到一组服务器的映射,而LBLC算法维护从一个目标IP地址到一台服务
器的映射。该算法根据请求的目标IP地址找出该目标IP地址对应的服务 器组,
按"最小连接"原则从服务器组中选出一台服务器,若服务器没有超载,将请求
发送到该服务器,若服务器超载;则按"最小连接"原则从这个集群中选出一 台
服务器,将该服务器加入到服务器组中,将请求发送到该服务器。同时,当该
服务器组有一段时间没有被修改,将最忙的服务器从服务器组中删除,以降低
复制的 程度。
Destination Hashing
"目标地址散列"调度算法根据请求的目标IP地址,作为散列键(Hash Key)从
静态分配的散列表找出对应的服务器,若该服务器是可用的且未超载,将请求
发送到该服务器,否则返回空。
Source Hashing
407
Distributed System Knowledge
"源地址散列"调度算法根据请求的源IP地址,作为散列键(Hash Key)从静态
分配的散列表找出对应的服务器,若该服务器是可用的且未超载,将请求发送
到该服务器,否则返回空。
ALU
Arithmetic Logical Unit can be regarded as the application logical services in
distributed system.
Data Storage
408
Behavior Questions
Behavior Question
Introduction
Behavior questions are very common in every interview. It is an important part to
evaluate you and company if both are fit in culture aspect.
Typical Questions
409
Behavior Questions
Knowledge, learn more about cutting-edge technology, talk about you like
learning.
Sense of achievement, conquer those tough problem.
Improvement on personal ability on multiple aspects.
Example:
I think I'm not a person like to convince somebody. I don't like to judge something.
I prefer to provide different aspects or solutions to other people instead of giving
them a judgment. There are lot of cases from me. But I think the most important
thing is trying to think more wider and more potential solutions. Do more evidence
research on that. Of course you can choose one aspect or solution you most
prefer, but firstly you need have more evidence to support that. Think about how
to convince yourself, then convince other people.
410
Behavior Questions
Keypoints:
Keypoints:
Example:
I'd like to talk about the experience when I did my research assistant. The
following are typical difficulties:
1. Took a project totally from other people's idea and build the program upon the
given prototype: It looks normal. Because when you enter a big company, this
is the similar scenario. You'll start to build something sophisticate from others'
idea and for others. But the idea on this project are based on many ideas
from previous research. Not only about the programming, but also some user
behavior and psychological research. Before everything start, you have to
read many paper then you can start to do something but you cannot make
excuse for slow progress. So quick learning across multiple fields to keep
making progress.
411
Behavior Questions
2. Deadline and requirement from professor: The retrieval process speed is not
ideal. When I almost finished the system, I need to reconstruct the system
architecture. Then I figure it out by using a kind of user profile and action
driven pattern. The data which concerning about user profile is loaded when
user login and the task and topic data indexing start when user begin to
choose their search task. So when user start to search, our indexed data is
already loaded and also only partial data which only support the current task
is loaded instead of load too much unnecessary data.
412
Behavior Questions
413
Questions on Past Projects
General Introduction
What (Overview) Non-technical brief intro.
Why (The Purpose)
Problems you want to resolve
Value of this project
How (Technical Backgroud)
Data
Services
Architecture
Individual Contribution
What you did?
Modules
Function
How you did?
Based on what kind of techniques
General Procedure
414
Questions on Past Projects
Group Difficulty
1. Trade-off communication
2. Deadline Dilemma (Completeness and Flawless)
415