0% found this document useful (0 votes)
320 views190 pages

Coding Interview in Java

This document contains a table of contents listing 125 coding interview problems and their corresponding page numbers. The problems cover topics like arrays, strings, linked lists, trees, graphs, sorting, searching, and dynamic programming. The page numbers range from 14 to 240.

Uploaded by

Hari Pedapati
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
Download as pdf or txt
0% found this document useful (0 votes)
320 views190 pages

Coding Interview in Java

This document contains a table of contents listing 125 coding interview problems and their corresponding page numbers. The problems cover topics like arrays, strings, linked lists, trees, graphs, sorting, searching, and dynamic programming. The page numbers range from 14 to 240.

Uploaded by

Hari Pedapati
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
Download as pdf or txt
Download as pdf or txt
You are on page 1/ 190

Contents

25 Shortest Word Distance III 50

26 Intersection of Two Arrays 52

27 Intersection of Two Arrays II 54


Contents 28 Two Sum II Input array is sorted 56

29 Two Sum III Data structure design 57

Coding Interview in Java 1

2
Remove Duplicates from Sorted Array

Remove Duplicates from Sorted Array II


14

16
30 3Sum

31 4Sum
58

60

32 3Sum Closest 62
3 Remove Element 18
33 Wiggle Sort 63
4 Move Zeroes 19
34 Wiggle Subsequence 64
5 Candy 20
35 Longest Common Prefix 65
6 Trapping Rain Water 22
36 Next Permutation 66
7 Product of Array Except Self 24
Program Creek 37 Search Insert Position 68
8 Minimum Size Subarray Sum 26
38 Median of Two Sorted Arrays 70
9 Summary Ranges 28
39 Find Minimum in Rotated Sorted Array 72
10 Missing Ranges 29
40 Find Minimum in Rotated Sorted Array II 74
11 Merge Intervals 30
41 Find First and Last Position of Element in Sorted Array 76
12 Insert Interval 31
42 Guess Number Higher or Lower 78
13 Partition Labels 34
43 First Bad Version 80
14 Find And Replace in String 36
44 Search in Rotated Sorted Array 82
15 One Edit Distance 37
45 Search in Rotated Sorted Array II 84
16 Merge Sorted Array 38
46 Longest Increasing Subsequence 85
17 Is Subsequence 40
47 Count of Smaller Numbers After Self 88
18 Backspace String Compare 41
48 Russian Doll Envelopes 91
19 Repeated String Match 43
49 HIndex 93
20 Container With Most Water 44
50 HIndex II 95
21 Reverse Vowels of a String 45
51 Valid Anagram 96
22 Valid Palindrome 46
52 Group Shifted Strings 98
23 Shortest Word Distance 47
53 Palindrome Pairs 100
24 Shortest Word Distance II 48
54 Line Reflection 102

2 | 568 Program Creek 3 | 568


Contents Contents Contents

55 Isomorphic Strings 103 85 Max Sum of Rectangle No Larger Than K 155 115 Number of Connected Components in an Undirected Graph 207

56 Two Sum 104 86 Maximum Sum of Subarray Close to K 158 116 Most Stones Removed with Same Row or Column 210

57 Maximum Size Subarray Sum Equals k 105 87 Sliding Window Maximum 160 117 Longest Increasing Path in a Matrix 213

58 Subarray Sum Equals K 107 88 Moving Average from Data Stream 162 118 Word Search 216

59 Maximum Subarray 108 89 Find Median from Data Stream 163 119 Word Search II 219

60 Maximum Product Subarray 111 90 Data Stream as Disjoint Intervals 165 120 Number of Islands 223

61 Longest Substring Without Repeating Characters 112 91 Linked List Random Node 167 121 Find a Path in a Matrix 226

62 Longest Substring with At Most K Distinct Characters 114 92 Shuffle an Array 168 122 Sudoku Solver 228

63 Substring with Concatenation of All Words 116 93 Sort List 170 123 Valid Sudoku 231

64 Minimum Window Substring 118 94 Quicksort Array in Java 172 124 Walls and Gates 233

65 Longest Substring with At Least K Repeating Characters 120 95 Kth Largest Element in an Array 175 125 Surrounded Regions 236

66 Permutation in String 122 96 Sort Colors 177 126 Set Matrix Zeroes 240

67 Longest Consecutive Sequence 124 97 Maximum Gap 178 127 Spiral Matrix 243

68 Majority Element 126 98 Group Anagrams 180 128 Spiral Matrix II 247

69 Majority Element II 128 99 Ugly Number 181 129 Rotate Image 249

70 Increasing Triplet Subsequence 129 100 Ugly Number II 182 130 Range Sum Query 2D Immutable 250

71 Find the Second Largest Number in an Array 131 101 Super Ugly Number 183 131 Shortest Distance from All Buildings 253

72 Word Ladder 132 102 Find K Pairs with Smallest Sums 184 132 Best Meeting Point 255

73 Word Ladder II 134 103 Rotate Array in Java 185 133 Game of Life 256

74 Top K Frequent Elements 136 104 Reverse Words in a String II 188 134 TicTacToe 258

75 Meeting Rooms II 139 105 Missing Number 189 135 Sparse Matrix Multiplication 261

76 Meeting Rooms 141 106 Find the Duplicate Number 190 136 Add Two Numbers 263

77 Range Addition 142 107 First Missing Positive 192 137 Reorder List 265

78 Merge K Sorted Arrays in Java 144 108 Queue Reconstruction by Height 194 138 Linked List Cycle 269

79 Merge k Sorted Lists 146 109 Binary Watch 195 139 Copy List with Random Pointer 270

80 Rearrange String k Distance Apart 147 110 Search a 2D Matrix 198 140 Merge Two Sorted Lists 272

81 Minimum Cost to Hire K Workers 149 111 Search a 2D Matrix II 199 141 Odd Even Linked List 274

82 Contains Duplicate 151 112 Kth Smallest Element in a Sorted Matrix 201 142 Remove Duplicates from Sorted List 276

83 Contains Duplicate II 152 113 Design Snake Game 203 143 Remove Duplicates from Sorted List II 278

84 Contains Duplicate III 153 114 Number of Islands II 205 144 Partition List 279

Program Creek 4 | 568 Program Creek 5 | 568 Program Creek 6 | 568


Contents Contents Contents

145 Intersection of Two Linked Lists 280 175 Balanced Binary Tree 337 205 Implement a Stack Using an Array in Java 399

146 Remove Linked List Elements 282 176 Symmetric Tree 339 206 Implement a Queue using an Array in Java 401

147 Swap Nodes in Pairs 283 177 Binary Search Tree Iterator 340 207 Evaluate Reverse Polish Notation 403

148 Reverse Linked List 285 178 Binary Tree Right Side View 342 208 Valid Parentheses 406

149 Reverse Linked List II 287 179 Lowest Common Ancestor of a Binary Search Tree 344 209 Longest Valid Parentheses 407

150 Reverse Double Linked List 289 180 Lowest Common Ancestor of a Binary Tree 345 210 Min Stack 408

151 Remove Nth Node From End of List 291 181 Most Frequent Subtree Sum 347 211 Max Chunks To Make Sorted 410

152 Palindrome Linked List 293 182 Verify Preorder Serialization of a Binary Tree 349 212 Maximal Rectangle 411

153 Delete Node in a Linked List 296 183 Populating Next Right Pointers in Each Node 351 213 Mini Parser 413

154 Reverse Nodes in kGroup 297 184 Populating Next Right Pointers in Each Node II 354 214 Flatten Nested List Iterator 415

155 Plus One Linked List 300 185 Unique Binary Search Trees 356 215 Nested List Weight Sum 417

156 Binary Tree Preorder Traversal 302 186 Unique Binary Search Trees II 358 216 Nested List Weight Sum II 419

157 Binary Tree Inorder Traversal 303 187 Sum Root to Leaf Numbers 360 217 Decode String 421

158 Binary Tree Postorder Traversal 305 188 Count Complete Tree Nodes 362 218 Evaluate math expression with plus, minus and parentheses 423

159 Binary Tree Level Order Traversal 308 189 Closest Binary Search Tree Value 365 219 Partition to K Equal Sum Subsets 425

160 Binary Tree Level Order Traversal II 310 190 Binary Tree Paths 367 220 Permutations 427

161 Binary Tree Vertical Order Traversal 312 191 Maximum Depth of Binary Tree 369 221 Permutations II 430

162 Invert Binary Tree 314 192 Recover Binary Search Tree 370 222 Permutation Sequence 432

163 Kth Smallest Element in a BST 315 193 Same Tree 371 223 Number of Squareful Arrays 434

164 Binary Tree Longest Consecutive Sequence 317 194 Serialize and Deserialize Binary Tree 372 224 Generate Parentheses 437

165 Validate Binary Search Tree 319 195 Inorder Successor in BST 375 225 Combination Sum 439

166 Flatten Binary Tree to Linked List 321 196 Inorder Successor in BST II 376 226 Combination Sum II 441

167 Path Sum 323 197 Find Leaves of Binary Tree 378 227 Combination Sum III 442

168 Path Sum II 325 198 Largest BST Subtree 380 228 Combination Sum IV 443

169 Construct Binary Tree from Inorder and Postorder Traversal 327 199 Implement Trie (Prefix Tree) 382 229 Wildcard Matching 444

170 Construct Binary Tree from Preorder and Inorder Traversal 329 200 Add and Search Word Data structure design 386 230 Regular Expression Matching 445

171 Convert Sorted Array to Binary Search Tree 331 201 Range Sum Query Mutable 390 231 Expressive Words 448

172 Convert Sorted List to Binary Search Tree 332 202 The Skyline Problem 394 232 Get Target Number Using Number List and Arithmetic Operations 450

173 Minimum Depth of Binary Tree 334 203 Implement Stack using Queues 396 233 Flip Game 452

174 Binary Tree Maximum Path Sum 336 204 Implement Queue using Stacks 398 234 Flip Game II 453

Program Creek 7 | 568 Program Creek 8 | 568 Program Creek 9 | 568


Contents Contents Contents

235 Word Pattern 454 265 Maximal Square 503 295 Course Schedule II 558

236 Word Pattern II 455 266 Minimum Path Sum 505 296 Minimum Height Trees 560

237 Scramble String 457 267 Unique Paths 507 297 Graph Valid Tree 562

238 Remove Invalid Parentheses 458 268 Unique Paths II 509 298 Clone Graph 564

239 Shortest Palindrome 460 269 Paint House 511 299 Reconstruct Itinerary 567

240 Lexicographical Numbers 462 270 Paint House II 513 300 Pow(x, n) 568

241 Combinations 464 271 Edit Distance in Java 515

242 Letter Combinations of a Phone Number 465 272 Distinct Subsequences Total 518

243 Restore IP Addresses 467 273 Longest Palindromic Substring 520

244 Factor Combinations 469 274 Longest Common Subsequence 522

245 Subsets 470 275 Longest Common Substring 524

246 Subsets II 472 276 LRU Cache 526

247 Coin Change 474 277 Insert Delete GetRandom O(1) 529

248 Palindrome Partitioning 477 278 Insert Delete GetRandom O(1) Duplicates allowed 531

249 Palindrome Partitioning II 479 279 Design a Data Structure with Insert, Delete and GetMostFrequent of O(1) 533

250 House Robber 480 280 Design Phone Directory 536

251 House Robber II 482 281 Design Twitter 537

252 House Robber III 483 282 Single Number 540

253 Jump Game 484 283 Single Number II 541

254 Jump Game II 486 284 Twitter Codility Problem Max Binary Gap 542

255 Best Time to Buy and Sell Stock 487 285 Number of 1 Bits 544

256 Best Time to Buy and Sell Stock II 488 286 Reverse Bits 545

257 Best Time to Buy and Sell Stock III 489 287 Repeated DNA Sequences 546

258 Best Time to Buy and Sell Stock IV 491 288 Bitwise AND of Numbers Range 548

259 Dungeon Game 493 289 Sum of Two Integers 549

260 Decode Ways 494 290 Counting Bits 550

261 Perfect Squares 495 291 Maximum Product of Word Lengths 552

262 Word Break 496 292 Gray Code 553

263 Word Break II 499 293 UTF8 Validation 554

264 Minimum Window Subsequence 502 294 Course Schedule 555

Program Creek 10 | 568 Program Creek 11 | 568 Program Creek 12 | 568


Contents 1 Remove Duplicates from Sorted Array

Every title in the PDF is linked back to the original blog. When it is clicked, it opens the original post in your Note that we only care about the first unique part of the original array. So it is ok if input array is 1, 2, 2, 3, 3,
browser. If you want to discuss any problem, please go to the post and leave your comment there. the array is changed to 1, 2, 3, 3, 3.
I’m not an expert and some solutions may not be optimal. So please leave your comment if you see any problem
or have a better solution. I will reply your comment as soon as I can.
This collection is updated from time to time. Please check out this link for the latest version: http://www.programcreek.com/
10-algorithms-for-coding-interview/
1 Remove Duplicates from Sorted Array
Given a sorted array, remove the duplicates in place such that each element appear only once and return the new
length. Do not allocate extra space for another array, you must do this in place with constant memory.
For example, given input array A = [1,1,2], your function should return length = 2, and A is now [1,2].

1.1 Analysis
The problem is pretty straightforward. It returns the length of the array with unique elements, but the original
array need to be changed also. This problem is similar to Remove Duplicates from Sorted Array II.

1.2 Java Solution

public static int removeDuplicates(int[] A) {


if (A.length < 2)
return A.length;

int j = 0;
int i = 1;

while (i < A.length) {


if (A[i] != A[j]) {
j++;
A[j] = A[i];
}

i++;
}

return j + 1;
}

Program Creek 13 | 568 14 | 568 Program Creek 15 | 568


2 Remove Duplicates from Sorted Array II

The problem with this solution is that there are 4 cases to handle. If we shift our two points to right by 1
element, the solution can be simplified as the Solution 2.

2.2 Java Solution 2


2 Remove Duplicates from Sorted Array II 3 Remove Element
public int removeDuplicates(int[] nums) {
Follow up for "Remove Duplicates": What if duplicates are allowed at most twice? if(nums==null){ Given an array and a value, remove all instances of that value in place and return the new length. (Note: The
For example, given sorted array A = [1,1,1,2,2,3], your function should return length = 5, and A is now [1,1,2,2,3]. return 0; order of elements can be changed. It doesn’t matter what you leave beyond the new length.)
So this problem also requires in-place array manipulation. }

if (nums.length <= 2){ 3.1 Java Solution


2.1 Java Solution 1 return nums.length;
} This problem can be solve by using two indices.
We can not change the given array’s size, so we only change the first k elements of the array which has duplicates /*
1,1,1,2,2,3 public int removeElement(int[] A, int elem) {
removed.
i j int i=0;
public int removeDuplicates(int[] nums) { */ int j=0;
if(nums==null){ int i = 1; // point to previous
return 0; int j = 2; // point to current while(j < A.length){
} if(A[j] != elem){
if(nums.length<3){ while (j < nums.length) { A[i] = A[j];
return nums.length; if (nums[j] == nums[i] && nums[j] == nums[i - 1]) { i++;
} j++; }
} else {
int i=0; i++; j++;
int j=1; nums[i] = nums[j]; }
/* j++;
} return i;
i, j 1 1 1 2 2 3 } }
step1 0 1 i j
step2 1 2 i j return i + 1;
step3 1 3 i j }
step4 2 4 i j

*/
while(j<nums.length){
if(nums[j]==nums[i]){
if(i==0){
i++;
j++;
}else if(nums[i]==nums[i-1]){
j++;
}else{
i++;
nums[i]=nums[j];
j++;
}
}else{
i++;
nums[i]=nums[j];
j++;
}
}

return i+1;
}

16 | 568 Program Creek 17 | 568 18 | 568


5 Candy

return result;
}

4 Move Zeroes 5 Candy


Given an array nums, write a function to move all 0’s to the end of it while maintaining the relative order of the There are N children standing in a line. Each child is assigned a rating value. You are giving candies to these
non-zero elements. children subjected to the following requirements:
For example, given nums = [0, 1, 0, 3, 12], after calling your function, nums should be [1, 3, 12, 0, 0]. 1. Each child must have at least one candy. 2. Children with a higher rating get more candies than their
neighbors.
What is the minimum candies you must give?
4.1 Java Solution 2
We can use the similar code that is used to solve Remove Duplicates from Sorted Array I, II, Remove Element. 5.1 Analysis
public void moveZeroes(int[] nums) { This problem can be solved in O(n) time.
int i=0; We can always assign a neighbor with 1 more if the neighbor has higher a rating value. However, to get the
int j=0;
minimum total number, we should always start adding 1s in the ascending order. We can solve this problem by
scanning the array from both sides. First, scan the array from left to right, and assign values for all the ascending
while(j<nums.length){
if(nums[j]==0){
pairs. Then scan from right to left and assign values to descending pairs.
j++; This problem is similar to Trapping Rain Water.
}else{
nums[i]=nums[j];
i++; 5.2 Java Solution
j++;
}
public int candy(int[] ratings) {
}
if (ratings == null || ratings.length == 0) {
return 0;
while(i<nums.length){
}
nums[i]=0;
i++;
int[] candies = new int[ratings.length];
}
candies[0] = 1;
}

//from let to right


for (int i = 1; i < ratings.length; i++) {
if (ratings[i] > ratings[i - 1]) {
candies[i] = candies[i - 1] + 1;
} else {
// if not ascending, assign 1
candies[i] = 1;
}
}

int result = candies[ratings.length - 1];

//from right to left


for (int i = ratings.length - 2; i >= 0; i--) {
int cur = 1;
if (ratings[i] > ratings[i + 1]) {
cur = candies[i + 1] + 1;
}

result += Math.max(cur, candies[i]);


candies[i] = cur;
}

19 | 568 20 | 568 Program Creek 21 | 568


6 Trapping Rain Water

}else{
left[i]=height[i];
max = height[i];
}
}
6 Trapping Rain Water 7 Product of Array Except Self
//scan from right to left
max = height[height.length-1];
Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how right[height.length-1]=height[height.length-1]; Given an array of n integers where n >1, nums, return an array output such that output[i] is equal to the product
much water it is able to trap after raining. for(int i=height.length-2; i>=0; i--){ of all the elements of nums except nums[i].
For example, given [0,1,0,2,1,0,1,3,2,1,2,1], return 6. if(height[i]<max){ Solve it without division and in O(n).
right[i]=max; For example, given [1,2,3,4], return [24,12,8,6].
}else{
6.1 Analysis right[i]=height[i];
max = height[i]; 7.1 Java Solution 1
This problem is similar to Candy. It can be solve by scanning from both sides and then get the total. }
}
public int[] productExceptSelf(int[] nums) {
6.2 Java Solution //calculate totoal int[] result = new int[nums.length];
for(int i=0; i<height.length; i++){
result+= Math.min(left[i],right[i])-height[i]; int[] t1 = new int[nums.length];
} int[] t2 = new int[nums.length];

return result; t1[0]=1;


} t2[nums.length-1]=1;

//scan from left to right


for(int i=0; i<nums.length-1; i++){
t1[i+1] = nums[i] * t1[i];
}

//scan from right to left


for(int i=nums.length-1; i>0; i--){
t2[i-1] = t2[i] * nums[i];
}

//multiply
for(int i=0; i<nums.length; i++){
result[i] = t1[i] * t2[i];
}

return result;
}
public int trap(int[] height) {
int result = 0;

if(height==null || height.length<=2) 7.2 Java Solution 2


return result;
We can directly put the product values into the final result array. This saves the extra space to store the 2
int left[] = new int[height.length];
intermediate arrays in Solution 1.
int right[]= new int[height.length];
public int[] productExceptSelf(int[] nums) {
//scan from left to right int[] result = new int[nums.length];
int max = height[0];
left[0] = height[0]; result[nums.length-1]=1;
for(int i=1; i<height.length; i++){ for(int i=nums.length-2; i>=0; i--){
if(height[i]<max){ result[i]=result[i+1]*nums[i+1];
left[i]=max; }

22 | 568 Program Creek 23 | 568 24 | 568


7 Product of Array Except Self 8 Minimum Size Subarray Sum

}
int left=1;
for(int i=0; i<nums.length; i++){ Similarly, we can also write it in a more readable way.
result[i]=result[i]*left;
left = left*nums[i]; public int minSubArrayLen(int s, int[] nums) {
} 8 Minimum Size Subarray Sum if(nums==null||nums.length==0)
return 0;
return result;
} Given an array of n positive integers and a positive integer s, find the minimal length of a subarray of which the int i=0;
sum ≥ s. If there isn’t one, return 0 instead. int j=0;
For example, given the array [2,3,1,2,4,3] and s = 7, the subarray [4,3] has the minimal length of 2 under the int sum=0;
problem constraint.
int minLen = Integer.MAX_VALUE;

8.1 Analysis while(j<nums.length){


if(sum<s){
We can use 2 points to mark the left and right boundaries of the sliding window. When the sum is greater than sum += nums[j];
the target, shift the left pointer; when the sum is less than the target, shift the right pointer. j++;
}else{
minLen = Math.min(minLen, j-i);
8.2 Java Solution - two pointers if(i==j-1)
return 1;
A simple sliding window solution.
sum -=nums[i];
public int minSubArrayLen(int s, int[] nums) { i++;
if(nums==null || nums.length==1) }
return 0; }

int result = nums.length; while(sum>=s){


minLen = Math.min(minLen, j-i);
int start=0;
int sum=0; sum -=nums[i++];
int i=0; }
boolean exists = false;
return minLen==Integer.MAX_VALUE? 0: minLen;
while(i<=nums.length){ }
if(sum>=s){
exists=true; //mark if there exists such a subarray
if(start==i-1){
return 1;
}

result = Math.min(result, i-start);


sum=sum-nums[start];
start++;

}else{
if(i==nums.length)
break;
sum = sum+nums[i];
i++;
}
}

if(exists)
return result;
else
return 0;

Program Creek 25 | 568 26 | 568 Program Creek 27 | 568


9 Summary Ranges 10 Missing Ranges 11 Merge Intervals
Given a sorted integer array without duplicates, return the summary of its ranges for consecutive numbers. Given a sorted integer array nums, where the range of elements are in the inclusive range [lower, upper], return Given a collection of intervals, merge all overlapping intervals.
For example, given [0,1,2,4,5,7], return ["0->2","4->5","7"]. its missing ranges. For example, Given [1,3],[2,6],[8,10],[15,18], return [1,6],[8,10],[15,18].
Example:
Input: nums = [0, 1, 3, 50, 75], lower = 0 and upper = 99, Output: ["2", "4->49", "51->74", "76->99"]
9.1 Analysis 11.1 Analysis
When iterating over the array, two values need to be tracked: 1) the first value of a new range and 2) the previous 10.1 Java Solution The key to solve this problem is defining a Comparator first to sort the arraylist of Intevals.
value in the range.

public List<String> findMissingRanges(int[] nums, int lower, int upper) { 11.2 Java Solution
9.2 Java Solution List<String> result = new ArrayList<>();
int start = lower;
public List<Interval> merge(List<Interval> intervals) {
public List<String> summaryRanges(int[] nums) { if(lower==Integer.MAX_VALUE){ if(intervals == null || intervals.size()<=1){
List<String> result = new ArrayList<String>(); return result; return intervals;
} }
if(nums == null || nums.length==0)
return result; for(int i=0; i<nums.length; i++){ Collections.sort(intervals, Comparator.comparing((Interval itl)->itl.start));
//handle duplicates, e.g., [1,1,1] lower=1 upper=1
if(nums.length==1){ if(i<nums.length-1 && nums[i]==nums[i+1]){ List<Interval> result = new ArrayList<>();
result.add(nums[0]+""); continue; Interval t = intervals.get(0);
} }
for(int i=1; i<intervals.size(); i++){
int pre = nums[0]; // previous element if(nums[i] == start){ Interval c = intervals.get(i);
int first = pre; // first element of each range start++; if(c.start <= t.end){
}else{ t.end = Math.max(t.end, c.end);
for(int i=1; i<nums.length; i++){ result.add(getRange(start, nums[i]-1)); }else{
if(nums[i]==pre+1){ if(nums[i]==Integer.MAX_VALUE){ result.add(t);
if(i==nums.length-1){ return result; t = c;
result.add(first+"->"+nums[i]); } }
} start = nums[i]+1; }
}else{ }
if(first == pre){ } result.add(t);
result.add(first+"");
}else{ if(start<=upper){ return result;
result.add(first + "->"+pre); result.add(getRange(start, upper)); }
} }

if(i==nums.length-1){ return result;


result.add(nums[i]+""); }
}
private String getRange(int n1, int n2) {
first = nums[i]; return n1 == n2 ? String.valueOf(n1) : String.format("%d->%d" , n1, n2);
} }

pre = nums[i];
}

return result;
}

28 | 568 29 | 568 30 | 568


12 Insert Interval 12 Insert Interval

* }
*/ return result;
public class Solution { }
public ArrayList<Interval> insert(ArrayList<Interval> intervals, Interval newInterval) {
public int helper(List<Interval> intervals, Interval newInterval) {
12 Insert Interval ArrayList<Interval> result = new ArrayList<Interval>(); int low = 0;
int high = intervals.size() - 1;
for(Interval interval: intervals){
Problem: if(interval.end < newInterval.start){ while (low < high) {
Given a set of non-overlapping & sorted intervals, insert a new interval into the intervals (merge if necessary). result.add(interval); int mid = low + (high - low) / 2;
}else if(interval.start > newInterval.end){
Example 1: result.add(newInterval); if (newInterval.start <= intervals.get(mid).start) {
Given intervals [1,3],[6,9], insert and merge [2,5] in as [1,5],[6,9]. newInterval = interval; high = mid;
}else if(interval.end >= newInterval.start || interval.start <= newInterval.end){ } else {
Example 2: newInterval = new Interval(Math.min(interval.start, newInterval.start), low = mid + 1;
Given [1,2],[3,5],[6,7],[8,10],[12,16], insert and merge [4,9] in as [1,2],[3,10],[12,16]. Math.max(newInterval.end, interval.end)); }
} }
This is because the new interval [4,9] overlaps with [3,5],[6,7],[8,10]. }
return high == 0 ? 0 : high - 1;
result.add(newInterval); }

12.1 Java Solution 1 return result; The best time is O(log(n)) and worst case time is O(n).
}
When iterating over the list, there are three cases for the current range. }

12.2 Java Solution 2 - Binary Search


If the intervals list is an ArrayList, we can use binary search to make the best search time complexity O(log(n)).
However, the worst time is bounded by shifting the array list if a new range needs to be inserted. So time
complexity is still O(n).

public List<Interval> insert(List<Interval> intervals, Interval newInterval) {


List<Interval> result = new ArrayList<>();

if (intervals.size() == 0) {
result.add(newInterval);
return result;
}

int p = helper(intervals, newInterval);


result.addAll(intervals.subList(0, p));

for (int i = p; i < intervals.size(); i++) {


Interval interval = intervals.get(i);
if (interval.end < newInterval.start) {
result.add(interval);
} else if (interval.start > newInterval.end) {
result.add(newInterval);
newInterval = interval;
/**
} else if (interval.end >= newInterval.start || interval.start <= newInterval.end) {
* Definition for an interval. newInterval = new Interval(Math.min(interval.start, newInterval.start),
* public class Interval { Math.max(newInterval.end, interval.end));
* int start;
}
* int end;
}
* Interval() { start = 0; end = 0; }
* Interval(int s, int e) { start = s; end = e; }
result.add(newInterval);

31 | 568 Program Creek 32 | 568 Program Creek 33 | 568


13 Partition Labels

int[] t = list.get(0);
for(int i=1; i<list.size(); i++){
int[] range = list.get(i);

13 Partition Labels if(range[1]<=t[1]){ 14 Find And Replace in String


continue;
}else if(range[0]>t[1]){ //impossible be equal
A string S of lowercase letters is given. We want to partition this string into as many parts as possible so that each result.add(t[1]-t[0]+1); To some string S, we will perform some replacement operations that replace groups of letters with new ones (not
letter appears in at most one part, and return a list of integers representing the size of these parts. t = range; necessarily the same size).
For example: }else{ Each replacement operation has 3 parameters: a starting index i, a source word x and a target word y. The rule
Input: S = "ababfeefhijkh" Output: [4,4,5] t[1] = range[1]; is that if x starts at position i in the original string S, then we will replace that occurrence of x with y. If not, we
Explanation: The partition is "abab", "feef", "hijkh". This is a partition so that each letter appears in at most one } do nothing.
part. } For example, if we have S = "abcd" and we have some replacement operation i = 2, x = "cd", y = "ffff", then
because "cd" starts at position 2 in the original string S, we will replace it with "ffff".
result.add(t[1]-t[0]+1);
13.1 Java Solution
return result;
14.1 Java Solution
}

public String findReplaceString(String S, int[] indexes, String[] sources, String[] targets) {


StringBuilder sb = new StringBuilder();
TreeMap<Integer, String[]> map = new TreeMap<>();
for (int i = 0; i < indexes.length; i++) {
map.put(indexes[i], new String[]{sources[i], targets[i]});
}

int prev = 0;

for (Map.Entry<Integer, String[]> entry : map.entrySet()) {


int startIndex = entry.getKey();
int endIndex = startIndex + entry.getValue()[0].length();

if (prev != startIndex) {
sb.append(S.substring(prev, startIndex));
}

String org = S.substring(startIndex, endIndex);


public List<Integer> partitionLabels(String S) { if (org.equals(entry.getValue()[0])) {
ArrayList<Integer> result = new ArrayList<>(); sb.append(entry.getValue()[1]);
prev = endIndex;
HashMap<Character, int[]> map = new HashMap<>(); } else {
for(int i=0; i<S.length(); i++){ sb.append(org);
char c = S.charAt(i); prev = endIndex;
int[] arr = map.get(c); }

if(arr == null){ }
arr = new int[]{i, i};
map.put(c, arr); if (prev < S.length()) {
}else{ sb.append(S.substring(prev));
arr[1]=i; }
}
} return sb.toString();
}
ArrayList<int[]> list = new ArrayList<>();
list.addAll(map.values());

Collections.sort(list, Comparator.comparing((int[] arr) -> arr[0]));

34 | 568 Program Creek 35 | 568 36 | 568


16 Merge Sorted Array

else
A[k--] = B[j--];
}
}

15 One Edit Distance 16 Merge Sorted Array


Given two strings S and T, determine if they are both one edit distance apart. Given two sorted integer arrays A and B, merge B into A as one sorted array.
Note: You may assume that A has enough space to hold additional elements from B. The number of elements
initialized in A and B are m and n respectively.
15.1 Java Solution

public boolean isOneEditDistance(String s, String t) {


16.1 Analysis
if(s==null || t==null)
return false;
The key to solve this problem is moving element of A and B backwards. If B has some elements left after A is
done, also need to handle that case.
int m = s.length(); The takeaway message from this problem is that the loop condition. This kind of condition is also used for
int n = t.length(); merging two sorted linked list.

if(Math.abs(m-n)>1){
return false; 16.2 Java Solution 1
}

int i=0; public class Solution {


int j=0; public void merge(int A[], int m, int B[], int n) {
int count=0;
while(m > 0 && n > 0){
while(i<m&&j<n){ if(A[m-1] > B[n-1]){
if(s.charAt(i)==t.charAt(j)){ A[m+n-1] = A[m-1];
i++; m--;
j++; }else{
}else{ A[m+n-1] = B[n-1];
count++; n--;
if(count>1) }
return false; }

if(m>n){ while(n > 0){


i++; A[m+n-1] = B[n-1];
}else if(m<n){ n--;
j++; }
}else{ }
i++; }
j++;
}
}
} 16.3 Java Solution 2

if(i<m||j<n){ The loop condition also can use m+n like the following.
count++;
public void merge(int A[], int m, int B[], int n) {
}
int i = m - 1;
int j = n - 1;
if(count==1)
int k = m + n - 1;
return true;

while (k >= 0) {
return false;
if (j < 0 || (i >= 0 && A[i] > B[j]))
}
A[k--] = A[i--];

37 | 568 38 | 568 Program Creek 39 | 568


18 Backspace String Compare

}else{
i--;
j--;
}
}else{
17 Is Subsequence 18 Backspace String Compare if(i>=0 || j>=0){
return false;
}
Given a string s and a string t, check if s is subsequence of t. Given two strings S and T, return if they are equal when both are typed into empty text editors. # means a }
You may assume that there is only lower case English letters in both s and t. t is potentially a very long (length backspace character. }
= 500,000) string, and s is a short string (<=100). Example 1:
A subsequence of a string is a new string which is formed from the original string by deleting some (can return i<0 && j<0;
Input: S = "ab#c", T = "ad#c" }
be none) of the characters without disturbing the relative positions of the remaining characters. (ie, "ace" is a
Output: true
subsequence of "abcde" while "aec" is not).
Explanation: Both S and T become "ac".

17.1 Java Solution Example 2:

Input: S = "a##c", T = "#a#c"


public boolean isSubsequence(String s, String t) { Output: true
if(s.length()==0) Explanation: Both S and T become "c".
return true;

int i=0;
int j=0; 18.1 Java Solution
while(i<s.length() && j<t.length()){
if(s.charAt(i)==t.charAt(j)){ This problem requires O(N) time and O(1) space.
i++;
public boolean backspaceCompare(String S, String T) {
}
int i = S.length()-1;
int j = T.length()-1;
j++;

while(i>=0 || j>=0){
if(i==s.length())
int c1=0;
return true;
while(i>=0 && (c1>0 || S.charAt(i)==’#’)){
}
if(S.charAt(i)==’#’){
c1++;
return false;
}else{
}
c1--;
}

i--;
}

int c2=0;
while(j>=0 && (c2>0 || T.charAt(j)==’#’)){
if(T.charAt(j)==’#’){
c2++;
}else{
c2--;
}

j--;
}

if(i>=0 && j>=0){


if(S.charAt(i)!=T.charAt(j)){
return false;

40 | 568 41 | 568 Program Creek 42 | 568


19 Repeated String Match 20 Container With Most Water 21 Reverse Vowels of a String
Given two strings A and B, find the minimum number of times A has to be repeated such that B is a substring of 20.1 Problem Write a function that takes a string as input and reverse only the vowels of a string.
it. If no such solution, return -1.
For example, with A = "abcd" and B = "cdabcdab". Given n non-negative integers a1, a2, ..., an, where each represents a point at coordinate (i, ai). n vertical lines are
Return 3, because by repeating A three times (“abcdabcdabcd”), B is a substring of it; and B is not a substring drawn such that the two endpoints of line i is at (i, ai) and (i, 0). Find two lines, which together with x-axis forms
21.1 Java Solution
of A repeated two times ("abcdabcd"). a container, such that the container contains the most water.
Note: The length of A and B will be between 1 and 10000. this is a simple problem which can be solved by using two pointers scanning from beginning and end of the array.

public String reverseVowels(String s) {


20.2 Analysis ArrayList<Character> vowList = new ArrayList<Character>();
19.1 Java Solution vowList.add(’a’);
Initially we can assume the result is 0. Then we scan from both sides. If leftHeight <rightHeight, move right and vowList.add(’e’);
The optimal solution’s time complexity is O(n) where n is the length of the longer string from A and B. find a value that is greater than leftHeight. Similarily, if leftHeight >rightHeight, move left and find a value that vowList.add(’i’);
is greater than rightHeight. Additionally, keep tracking the max value. vowList.add(’o’);
public int repeatedStringMatch(String A, String B) {
vowList.add(’u’);
int i = 0;
vowList.add(’A’);
int j = 0;
vowList.add(’E’);
vowList.add(’I’);
int result = 0;
vowList.add(’O’);
int k = 0;
vowList.add(’U’);

while (j < B.length()) {


char[] arr = s.toCharArray();
if (A.charAt(i) == B.charAt(j)) {
i++;
int i=0;
j++;
int j=s.length()-1;

if (i == A.length()) {
while(i<j){
i = 0;
if(!vowList.contains(arr[i])){
result++;
i++;
} 20.3 Java Solution continue;
} else {
}
k++;
if (k == A.length()) { public int maxArea(int[] height) {
if (height == null || height.length < 2) { if(!vowList.contains(arr[j])){
return -1;
return 0; j--;
}
} continue;
i = k;
}
j = 0;
result = 0; int max = 0;
int left = 0; char t = arr[i];
}
int right = height.length - 1; arr[i]=arr[j];
}
arr[j]=t;

if (i > 0) { while (left < right) {


max = Math.max(max, (right - left) * Math.min(height[left], height[right])); i++;
result++;
if (height[left] < height[right]) j--;
}
left++; }

return result; else


right--; return new String(arr);
}
} }

return max;
}

43 | 568 44 | 568 45 | 568


22 Valid Palindrome 23 Shortest Word Distance 24 Shortest Word Distance II
Given a string, determine if it is a palindrome, considering only alphanumeric characters and ignoring cases. Given a list of words and two words word1 and word2, return the shortest distance between these two words in This is a follow up of Shortest Word Distance. The only difference is now you are given the list of words and
For example, "Red rum, sir, is murder" is a palindrome, while "Programcreek is awesome" is not. the list. your method will be called repeatedly many times with different parameters. How would you optimize it?
Note: Have you consider that the string might be empty? This is a good question to ask during an interview. For example, Assume that words = ["practice", "makes", "perfect", "coding", "makes"]. Design a class which receives a list of words in the constructor, and implements a method that takes two words
For the purpose of this problem, we define empty string as valid palindrome. Given word1 = “coding”, word2 = “practice”, return 3. Given word1 = "makes", word2 = "coding", return 1. word1 and word2 and return the shortest distance between these two words in the list.
For example, Assume that words = ["practice", "makes", "perfect", "coding", "makes"].
Given word1 = “coding”, word2 = “practice”, return 3. Given word1 = "makes", word2 = "coding", return 1.
22.1 Java Solution 23.1 Java Solution
There are several different ways to solve this problem. The following is a solution with O(n) time complexity and 24.1 Java Solution
public int shortestDistance(String[] words, String word1, String word2) {
O(1) space complexity.
int m=-1;
public boolean isPalindrome(String s) { int n=-1; public class WordDistance {
if(s==null){ HashMap<String, ArrayList<Integer>> map;
return false; int min = Integer.MAX_VALUE; public WordDistance(String[] words) {
} map = new HashMap<String, ArrayList<Integer>>();
for(int i=0; i<words.length; i++){ for(int i=0; i<words.length; i++){
s = s.toLowerCase(); String s = words[i]; if(map.containsKey(words[i])){
if(word1.equals(s)){ map.get(words[i]).add(i);
int i=0; m = i; }else{
int j=s.length()-1; if(n!=-1) ArrayList<Integer> list = new ArrayList<Integer>();
min = Math.min(min, m-n); list.add(i);
while(i<j){ }else if(word2.equals(s)){ map.put(words[i], list);
while(i<j && !((s.charAt(i)>=’a’ && s.charAt(i)<=’z’) n = i; }
|| (s.charAt(i)>=’0’&&s.charAt(i)<=’9’))){ if(m!=-1) }
i++; min = Math.min(min, n-m); }
} }
} public int shortest(String word1, String word2) {
while(i<j && !((s.charAt(j)>=’a’ && s.charAt(j)<=’z’)
|| (s.charAt(j)>=’0’&&s.charAt(j)<=’9’))){ return min; ArrayList<Integer> l1 = map.get(word1);
j--; } ArrayList<Integer> l2 = map.get(word2);
}
int result = Integer.MAX_VALUE;
if(s.charAt(i) != s.charAt(j)){ for(int i1: l1){
return false; for(int i2: l2){
} result = Math.min(result, Math.abs(i1-i2));
}
i++; }
j--; return result;
} }
}
return true;
} The time complexity for shortest method is O(M*N), where M is freqency of word1 and N is the frequency of
word2. This can be improved by the following:

public int shortest(String word1, String word2) {

ArrayList<Integer> l1 = map.get(word1);
ArrayList<Integer> l2 = map.get(word2);

int result = Integer.MAX_VALUE;

46 | 568 47 | 568 48 | 568


24 Shortest Word Distance II 25 Shortest Word Distance III

int i=0;
int j=0; public int shortestWordDistance(String[] words, String word1, String word2) {
while(i<l1.size() && j<l2.size()){ if(words==null||words.length==0)
result = Math.min(result, Math.abs(l1.get(i)-l2.get(j))); return -1;
if(l1.get(i)<l2.get(j)){
i++; 25 Shortest Word Distance III if(word1==null || word2==null)
}else{ return -1;
j++;
} This is a follow-up problem of Shortest Word Distance. The only difference is now word1 could be the same as boolean isSame = false;
} word2.
Given a list of words and two words word1 and word2, return the shortest distance between these two words if(word1.equals(word2))
return result; in the list. isSame = true;
} word1 and word2 may be the same and they represent two individual words in the list.
int shortest= Integer.MAX_VALUE;
For example, Assume that words = ["practice", "makes", "perfect", "coding", "makes"].
The time complexity of the shortest method is now O(M+N). Since M+N <size of word list, the time is O(K) Given word1 = “makes”, word2 = “coding”, return 1. Given word1 = "makes", word2 = "makes", return 3. int prev=-1;
where k is the list size.
int i1=-1;
int i2=-1;
25.1 Java Solution 1
for(int i=0; i<words.length; i++){
In this problem, word1 and word2 can be the same. The two variables used to track indices should take turns to if(isSame){
update. if(words[i].equals(word1)){
if(prev!=-1){
public int shortestWordDistance(String[] words, String word1, String word2) {
shortest=Math.min(shortest, i-prev);
if(words==null || words.length<1 || word1==null || word2==null)
}
return 0;
prev = i;
}
int m=-1;
}else{
int n=-1;
if(word1.equals(words[i])){
i1=i;
int min = Integer.MAX_VALUE;
if(i2!=-1){
int turn=0;
shortest = Math.min(shortest, i-i2);
if(word1.equals(word2))
}
turn = 1;
}else if(word2.equals(words[i])){
i2=i;
for(int i=0; i<words.length; i++){
if(i1!=-1){
String s = words[i];
shortest = Math.min(shortest, i-i1);
if(word1.equals(s) && (turn ==1 || turn==0)){
}
m = i;
}
if(turn==1) turn=2;
}
if(n!=-1)
}
min = Math.min(min, m-n);
}else if(word2.equals(s) && (turn==2 || turn==0)){
return shortest;
n = i;
}
if(turn==2) turn =1;
if(m!=-1)
min = Math.min(min, n-m);
}
}

return min;
}

25.2 Java Solution 2


We can divide the cases to two: word1 and word2 are the same and not the same.

Program Creek 49 | 568 50 | 568 Program Creek 51 | 568


26 Intersection of Two Arrays

for(int i: list){
result[k++] = i;
}

return result;
26 Intersection of Two Arrays } 27 Intersection of Two Arrays II
Given two arrays, write a function to compute their intersection. Given two arrays, write a function to compute their intersection.
26.3 Any improvement? Example: Given nums1 = [1, 2, 2, 1], nums2 = [2, 2], return [2, 2].

26.1 Java Solution 1 - HashSet


27.1 Java Solution 1
Time = O(n). Space = O(n).

public int[] intersection(int[] nums1, int[] nums2) { public int[] intersect(int[] nums1, int[] nums2) {
HashSet<Integer> set1 = new HashSet<Integer>(); HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
for(int i: nums1){ for(int i: nums1){
set1.add(i); if(map.containsKey(i)){
} map.put(i, map.get(i)+1);
}else{
HashSet<Integer> set2 = new HashSet<Integer>(); map.put(i, 1);
for(int i: nums2){ }
if(set1.contains(i)){ }
set2.add(i);
} ArrayList<Integer> list = new ArrayList<Integer>();
} for(int i: nums2){
if(map.containsKey(i)){
int[] result = new int[set2.size()]; if(map.get(i)>1){
int i=0; map.put(i, map.get(i)-1);
for(int n: set2){ }else{
result[i++] = n; map.remove(i);
} }
list.add(i);
return result; }
} }

int[] result = new int[list.size()];


int i =0;
26.2 Java Solution 2 - Binary Search while(i<list.size()){
result[i]=list.get(i);
Time = O(nlog(n)). Space = O(n). i++;
}
public int[] intersection(int[] nums1, int[] nums2) {
Arrays.sort(nums1); return result;
Arrays.sort(nums2); }

ArrayList<Integer> list = new ArrayList<Integer>();


for(int i=0; i<nums1.length; i++){
if(i==0 || (i>0 && nums1[i]!=nums1[i-1])){ 27.2 Java Solution 2
if(Arrays.binarySearch(nums2, nums1[i])>-1){
list.add(nums1[i]); If the arrays are sorted, then we can use two points.
}
} public int[] intersect(int[] nums1, int[] nums2) {
} Arrays.sort(nums1);
Arrays.sort(nums2);
int[] result = new int[list.size()]; ArrayList<Integer> list = new ArrayList<Integer>();
int k=0; int p1=0, p2=0;

52 | 568 Program Creek 53 | 568 54 | 568


27 Intersection of Two Arrays II

while(p1<nums1.length && p2<nums2.length){


if(nums1[p1]<nums2[p2]){
p1++;
}else if(nums1[p1]>nums2[p2]){
p2++;
}else{ 28 Two Sum II Input array is sorted 29 Two Sum III Data structure design
list.add(nums1[p1]);
p1++;
p2++; This problem is similar to Two Sum. Design and implement a TwoSum class. It should support the following operations: add and find.
To solve this problem, we can use two pointers to scan the array from both sides. See Java solution below: add - Add the number to an internal data structure. find - Find if there exists any pair of numbers which sum
} is equal to the value.
public int[] twoSum(int[] numbers, int target) {
} For example,
if (numbers == null || numbers.length == 0)
int[] result = new int[list.size()]; return null; add(1);
int i=0; add(3);
while(i<list.size()){ int i = 0; add(5);
result[i]=list.get(i); int j = numbers.length - 1; find(4) -> true
i++; find(7) -> false
} while (i < j) {
return result; int x = numbers[i] + numbers[j];
} if (x < target) {
++i; 29.1 Java Solution
} else if (x > target) {
j--; Since the desired class need add and get operations, HashMap is a good option for this purpose.
} else {
return new int[] { i + 1, j + 1 }; public class TwoSum {
} private HashMap<Integer, Integer> elements = new HashMap<Integer, Integer>();
}
public void add(int number) {
return null; if (elements.containsKey(number)) {
} elements.put(number, elements.get(number) + 1);
} else {
elements.put(number, 1);
}
}

public boolean find(int value) {


for (Integer i : elements.keySet()) {
int target = value - i;
if (elements.containsKey(target)) {
if (i == target && elements.get(target) < 2) {
continue;
}
return true;
}
}
return false;
}
}

Program Creek 55 | 568 56 | 568 57 | 568


30 3Sum

k--;
}
}
}

30 3Sum return result; 31 4Sum


}

Problem: Given an array S of n integers, are there elements a, b, c, and d in S such that a + b + c + d = target? Find all
Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all unique triplets in the unique quadruplets in the array which gives the sum of target.
array which gives the sum of zero. Note: Elements in a quadruplet (a,b,c,d) must be in non-descending order. (ie, a ≤ b ≤ c ≤ d) The solution set
Note: Elements in a triplet (a,b,c) must be in non-descending order. (ie, a ≤ b ≤ c) The solution set must not must not contain duplicate quadruplets.
contain duplicate triplets.
For example, given array S = {1 0 -1 0 -2 2}, and target = 0.
For example, given array S = {-1 0 1 2 -1 -4},
A solution set is:
A solution set is: (-1, 0, 0, 1)
(-1, 0, 1) (-2, -1, 1, 2)
(-1, -1, 2) (-2, 0, 0, 2)

30.1 Java Solution 31.1 Java Solution


This problem can be solved by using two pointers. Time complexity is O(n2̂). A typical k-sum problem. Time is N to the power of (k-1).
To avoid duplicate, we can take advantage of sorted arrays, i.e., move pointers by >1 to use same element only
public List<List<Integer>> fourSum(int[] nums, int target) {
once.
List<List<Integer>> result = new ArrayList<List<Integer>>();
public List<List<Integer>> threeSum(int[] nums) {
Arrays.sort(nums); if(nums==null|| nums.length<4)
return result;
ArrayList<List<Integer>> result = new ArrayList<>();
Arrays.sort(nums);
for (int i = 0; i < nums.length; i++) {
int j = i + 1; for(int i=0; i<nums.length-3; i++){
int k = nums.length - 1; if(i!=0 && nums[i]==nums[i-1])
continue;
if (i > 0 && nums[i] == nums[i - 1]) { for(int j=i+1; j<nums.length-2; j++){
continue; if(j!=i+1 && nums[j]==nums[j-1])
} continue;
int k=j+1;
while (j < k) { int l=nums.length-1;
if (k < nums.length - 1 && nums[k] == nums[k + 1]) { while(k<l){
k--; if(nums[i]+nums[j]+nums[k]+nums[l]<target){
continue; k++;
} }else if(nums[i]+nums[j]+nums[k]+nums[l]>target){
l--;
if (nums[i] + nums[j] + nums[k] > 0) { }else{
k--; List<Integer> t = new ArrayList<Integer>();
} else if (nums[i] + nums[j] + nums[k] < 0) { t.add(nums[i]);
j++; t.add(nums[j]);
} else { t.add(nums[k]);
ArrayList<Integer> l = new ArrayList<>(); t.add(nums[l]);
l.add(nums[i]); result.add(t);
l.add(nums[j]);
l.add(nums[k]); k++;
result.add(l); l--;
j++;

58 | 568 Program Creek 59 | 568 60 | 568


31 4Sum

while(k<l &&nums[l]==nums[l+1] ){
l--;
}

while(k<l &&nums[k]==nums[k-1]){
k++; 32 3Sum Closest 33 Wiggle Sort
}
}
Given an array S of n integers, find three integers in S such that the sum is closest to a given number, target. Given an unsorted array nums, reorder it in-place such that nums[0] <nums[1] >nums[2] <nums[3].... Example:
Return the sum of the three integers. You may assume that each input would have exactly one solution.
Input: nums = [3,5,2,1,6,4]
}
For example, given array S = {-1 2 1 -4}, and target = 1. Output: One possible answer is [3,5,1,6,2,4]
}
} The sum that is closest to the target is 2. (-1 + 2 + 1 = 2).

return result;
} 33.1 Java Solution
32.1 Analysis
public void wiggleSort(int[] nums) {
This problem is similar to 2 Sum. This kind of problem can be solved by using a similar approach, i.e., two
if (nums == null || nums.length <= 1) {
pointers from both left and right.
return;
}

32.2 Java Solution for (int i = 1; i < nums.length; i++) {


if (i % 2 == 1) {
public int threeSumClosest(int[] nums, int target) { if (nums[i - 1] > nums[i]) {
int min = Integer.MAX_VALUE; swap(nums, i - 1, i);
int result = 0; }
} else {
Arrays.sort(nums); if (nums[i - 1] < nums[i]) {
swap(nums, i - 1, i);
for (int i = 0; i < nums.length; i++) { }
int j = i + 1; }
int k = nums.length - 1; }
while (j < k) { }
int sum = nums[i] + nums[j] + nums[k];
int diff = Math.abs(sum - target); private void swap(int[] nums, int i, int j) {
int t = nums[i];
if(diff == 0) return sum; nums[i] = nums[j];
nums[j] = t;
if (diff < min) { }
min = diff;
result = sum;
}
if (sum <= target) {
j++;
} else {
k--;
}
}
}

return result;
}

Time Complexity is O(n2̂).

Program Creek 61 | 568 62 | 568 63 | 568


34 Wiggle Subsequence 35 Longest Common Prefix 36 Next Permutation
Given a sequence of integers, return the length of the longest subsequence that is a wiggle sequence. A sub- Implement next permutation, which rearranges numbers into the lexicographically next greater permutation of
35.1 Problem
sequence is obtained by deleting some number of elements (eventually, also zero) from the original sequence, numbers.
leaving the remaining elements in their original order. Write a function to find the longest common prefix string amongst an array of strings. If such arrangement is not possible, it must rearrange it as the lowest possible order (ie, sorted in ascending
order). The replacement must be in-place, do not allocate extra memory.
Here are some examples. Inputs are in the left-hand column and its corresponding outputs are in the right-hand
34.1 Java Solution 35.2 Analysis column.

The problem is converted to finding the turning point. When nums[i] <nums[i+1], we want to keep going to the To solve this problem, we need to find the two loop conditions. One is the length of the shortest string. The other 1,2,3 [U+FFFD] 1,3,2
right until finding the largest one, which is the turning point. Similarly, when nums[i] >nums[i+1], we want to 3,2,1 [U+FFFD] 1,2,3
is iteration over every element of the string array.
keep going to the right until finding the smallest one, which is the turning point. We always want to use the 1,1,5 [U+FFFD] 1,5,1
largest or smallest as the turning point because that guarantees the optimal solution.
35.3 Java Solution
public int wiggleMaxLength(int[] nums) {
if(nums == null || nums.length==0) 36.1 Analysis
return 0; public String longestCommonPrefix(String[] strs) {
if(nums.length<2){ if(strs==null || strs.length ==0){ The steps to solve this problem: 1) scan from right to left, find the first element that is less than its previous one.
return nums.length; return "";
} } 4 5 6 3 2 1
|
int count=1; if(strs.length == 1){ p
return strs[0];
} 2) scan from right to left, find the first element that is greater than p.
for(int i=1, j=0; i<nums.length; j=i, i++){
if(nums[j]<nums[i]){ 4 5 6 3 2 1
int i=0;
count++; |
while(true){
while(i<nums.length-1 && nums[i]<=nums[i+1]){ q
boolean flag = true;
i++; for(int j=1; j<strs.length; j++){
} if(strs[j].length()<=i || strs[j-1].length() <=i 3) swap p and q
}else if(nums[j]>nums[i]){ || strs[j].charAt(i) != strs[j-1].charAt(i)){
count++; 4 5 6 3 2 1
flag = false;
while(i<nums.length-1 && nums[i]>=nums[i+1]){ swap
break;
i++; 4 6 5 3 2 1
}
} }
} 4) reverse elements [p+1, nums.length]
} if(flag){
4 6 1 2 3 5
i++;
return count; }else{
} break;
}
}
36.2 Java Solution

return strs[0].substring(0, i);


public void nextPermutation(int[] nums) {
}
//find first decreasing digit
int mark = -1;
for (int i = nums.length - 1; i > 0; i--) {
if (nums[i] > nums[i - 1]) {
mark = i - 1;
break;
}

64 | 568 65 | 568 66 | 568


36 Next Permutation 37 Search Insert Position

} }
}
if (mark == -1) {
reverse(nums, 0, nums.length - 1); return i;
return; }
} 37 Search Insert Position
int idx = nums.length-1;
for (int i = nums.length-1; i >= mark+1; i--) { Given a sorted array and a target value, return the index if the target is found. If not, return the index where it
if (nums[i] > nums[mark]) { would be if it were inserted in order. You may assume no duplicates in the array.
idx = i; Here are few examples.
break;
} [1,3,5,6], 5 -> 2
} [1,3,5,6], 2 -> 1
[1,3,5,6], 7 -> 4
swap(nums, mark, idx); [1,3,5,6], 0 -> 0

reverse(nums, mark + 1, nums.length - 1);


}
37.1 Java Solution
private void swap(int[] nums, int i, int j) {
int t = nums[i]; This is a binary search problem. The complexity should be O(log(n)).
nums[i] = nums[j];
nums[j] = t; public int searchInsert(int[] nums, int target) {
} if(target>nums[nums.length-1]){
return nums.length;
private void reverse(int[] nums, int i, int j) { }
while (i < j) {
swap(nums, i, j); int l=0;
i++; int r=nums.length-1;
j--;
} while(l<r){
} int m = l+(r-l)/2;
if(target>nums[m]){
l=m+1;
}else{
r=m;
}
}

return l;
}

Or similarly, we can write the solution like the following:

public int searchInsert(int[] nums, int target) {


int i=0;
int j=nums.length-1;

while(i<=j){
int mid = (i+j)/2;

if(target > nums[mid]){


i=mid+1;
}else if(target < nums[mid]){
j=mid-1;
}else{
return mid;

Program Creek 67 | 568 68 | 568 Program Creek 69 | 568


38 Median of Two Sorted Arrays

j1 = m1;
i2 = m2+1;
}

return getKth(nums1, i1, j1, nums2, i2, j2, k);


38 Median of Two Sorted Arrays } 39 Find Minimum in Rotated Sorted Array
The main challenge is to calculate the middle elements, we can not do the following like a regular binary search:
There are two sorted arrays A and B of size m and n respectively. Find the median of the two sorted arrays. The overall Suppose a sorted array is rotated at some pivot unknown to you beforehand. (i.e., 0 1 2 4 5 6 7 might become 4 5
run time complexity should be O(log (m+n)). int m1 = i1+(j1-i1)/2; 6 7 0 1 2).
int m2 = i2+(j2-i2)/2; Find the minimum element.You may assume no duplicate exists in the array.

38.1 Java Solution It will result in either dead loop or missing the element at the beginning. The key is we always drop <= half
size of the elements. 39.1 Analysis
This problem can be converted to the problem of finding kth element, k is (A’s length + B’ Length)/2.
If any of the two arrays is empty, then the kth element is the non-empty array’s kth element. If k == 0, the kth This problem is a binary search and the key is breaking the array to two parts, so that we can work on half of the
element is the first element of A or B. array each time.
For normal cases(all other cases), we need to move the pointer at the pace of half of the array size to get If we pick the middle element, we can compare the middle element with the leftmost (or rightmost) element. If
O(log(n)) time. the middle element is less than leftmost, the left half should be selected; if the middle element is greater than the
leftmost (or rightmost), the right half should be selected. Using recursion or iteration, this problem can be solved
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
in time log(n).
int total = nums1.length+nums2.length;
In addition, in any rotated sorted array, the rightmost element should be less than the left-most element,
if(total%2==0){
otherwise, the sorted array is not rotated and we can simply pick the leftmost element as the minimum.
return (getKth(nums1, 0, nums1.length-1, nums2, 0, nums2.length-1, total/2)
+ getKth(nums1, 0, nums1.length-1, nums2, 0, nums2.length-1, total/2-1))/2.0;
}else{
return getKth(nums1,0, nums1.length-1, nums2, 0, nums2.length-1, total/2);
}
}

//k is the index starting from 0


private int getKth(int[] nums1, int i1, int j1, int[] nums2, int i2, int j2, int k){
if(j1<i1){
return nums2[i2+k];
}
if(j2<i2){
return nums1[i1+k];
}

if(k==0){
return Math.min(nums1[i1], nums2[i2]);
}

int len1 = j1 - i1 + 1;
int len2 = j2 - i2 + 1;

int m1 = k*len1/(len1+len2);
int m2 = k - m1 - 1;

m1 += i1;
m2 += i2;

if(nums1[m1]<nums2[m2]){
k = k-(m1-i1+1); 39.2 Java Solution 1 - Recursion
j2 = m2;
i1 = m1+1; Define a helper function, otherwise, we will need to use Arrays.copyOfRange() function, which may be expensive
}else{ for large arrays.
k = k-(m2-i2+1);

70 | 568 Program Creek 71 | 568 72 | 568


39 Find Minimum in Rotated Sorted Array 40 Find Minimum in Rotated Sorted Array II

public int findMin(int[] num) { //handle cases like [3, 1, 3]


return findMin(num, 0, num.length - 1); while(nums[i]==nums[j] && i!=j){
} i++;
}
public int findMin(int[] num, int left, int right) { 40 Find Minimum in Rotated Sorted Array II
if (left == right) if(nums[i]<=nums[j]){
return num[left]; return nums[i];
if ((right - left) == 1) Follow up for "Find Minimum in Rotated Sorted Array": What if duplicates are allowed? }
return Math.min(num[left], num[right]); Would this affect the run-time complexity? How and why?
int m=(i+j)/2;
int middle = left + (right - left) / 2; if(nums[m]>=nums[i]){
40.1 Java Solution 1 - Recursion i=m+1;
// not rotated }else{
if (num[left] < num[right]) { This is a follow-up problem of finding minimum element in rotated sorted array without duplicate elements. We j=m;
return num[left]; only need to add one more condition, which checks if the left-most element and the right-most element are equal. }
If they are we can simply drop one of them. In my solution below, I drop the left element whenever the left-most }
// go right side
equals to the right-most.
} else if (num[middle] > num[left]) { return -1;
return findMin(num, middle, right); public int findMin(int[] num) { }
return findMin(num, 0, num.length-1);
// go left side }
} else {
return findMin(num, left, middle); public int findMin(int[] num, int left, int right){
} if(right==left){
} return num[left];
}
if(right == left +1){
return Math.min(num[left], num[right]);
39.3 Java Solution 2 - Iteration }
// 3 3 1 3 3 3

/*
int middle = (right-left)/2 + left;
To understand the boundaries, use the following 3 examples:
// already sorted
[2,1], [2,3,1], [3,1,2]
if(num[right] > num[left]){
*/ return num[left];
public int findMin(int[] nums) {
//right shift one
if(nums==null || nums.length==0)
}else if(num[right] == num[left]){
return -1;
return findMin(num, left+1, right);
//go right
int i=0;
}else if(num[middle] >= num[left]){
int j=nums.length-1;
return findMin(num, middle, right);
//go left
while(i<=j){
}else{
if(nums[i]<=nums[j])
return findMin(num, left, middle);
return nums[i];
}
}
int m=(i+j)/2;

if(nums[m]>=nums[i]){
i=m+1;
}else{
40.2 Java Solution 2 - Iteration
j=m;
} public int findMin(int[] nums) {
} int i=0;
int j=nums.length-1;
return -1;
} while(i<=j){

Program Creek 73 | 568 74 | 568 Program Creek 75 | 568


41 Find First and Last Position of Element in Sorted Array

41.3 Java Solution 2 - (Deprecated)

public int[] searchRange(int[] nums, int target) {


if(nums == null || nums.length == 0){
41 Find First and Last Position of Element in return null; 42 Guess Number Higher or Lower
}
Sorted Array int[] arr= new int[2]; We are playing the Guess Game. The game is as follows:
arr[0]=-1; I pick a number from 1 to n. You have to guess which number I picked.
Given a sorted array of integers, find the starting and ending position of a given target value. Your algorithm’s arr[1]=-1; Every time you guess wrong, I’ll tell you whether the number is higher or lower.
runtime complexity must be in the order of O(log n). If the target is not found in the array, return [-1, -1]. For You call a pre-defined API guess(int num) which returns 3 possible results (-1, 1, or 0):
binarySearch(nums, 0, nums.length-1, target, arr);
example, given [5, 7, 7, 8, 8, 10] and target value 8, return [3, 4]. -1 : My number is lower 1 : My number is higher 0 : Congrats! You got it! Example: n = 10, I pick 6.
Return 6.
return arr;
}
41.1 Analysis
public void binarySearch(int[] nums, int left, int right, int target, int[] arr){
42.1 Java Solution
Based on the requirement of O(log n), this is a binary search problem apparently.
if(right<left)
This is a typical binary search problem. Here is a Java solution.
return;

41.2 Java Solution 1 - Log(n) if(nums[left]==nums[right] && nums[left]==target){


public int guessNumber(int n) {
int low=1;
arr[0]=left;
We can first find the start and then the end of the target. int high=n;
arr[1]=right;
return;
public int[] searchRange(int[] nums, int target) { while(low <= high){
}
int l=0; int mid = low+((high-low)/2);
int r=nums.length-1; int result = guess(mid);
int mid = left+(right-left)/2;
if(result==0){
while(l<r){ return mid;
int m=l+(r-l)/2; }else if(result==1){
if(nums[mid]<target){
if(nums[m]<target){ low = mid+1;
binarySearch(nums, mid+1, right, target, arr);
l=m+1; }else{
}else if(nums[mid]>target){
}else{ high=mid-1;
binarySearch(nums, left, mid-1, target, arr);
r=m; }
}else{
} }
arr[0]=mid;
}
arr[1]=mid;
return -1;
int first=l; }
//handle duplicates - left
if(l<nums.length&&nums[l]==target){//l is in boundary and is the target
int t1 = mid;
l=0;
while(t1 >left && nums[t1]==nums[t1-1]){
r=nums.length-1;
t1--;
while(l<r){ 42.2 What we learn from this problem?
arr[0]=t1;
int m=l+(r-l+1)/2;
}
if(nums[m]>target){ low+(high-low)/2 yields the same value with (low+high)/2. However, the first expression is less expensive. In
r=m-1; addition, the following expression can be used:
//handle duplicates - right
}else{
int t2 = mid;
l=m; low+((high-low)>>1)
while(t2 < right&& nums[t2]==nums[t2+1]){
} (low+high)>>>1
t2++;
}
arr[1]=t2;
Under the assumption that high and low are both non-negative, we know for sure that the upper-most bit (the
}
return new int[]{first, r}; sign-bit) is zero.
return;
} So both high and low are in fact 31-bit integers.
}
}
return new int[]{-1,-1}; high = 0100 0000 0000 0000 0000 0000 0000 0000 = 1073741824
} low = 0100 0000 0000 0000 0000 0000 0000 0000 = 1073741824
In the worst case, the time of the second solution is actually O(n).
When you add them together they may "spill" over into the top-bit.

76 | 568 Program Creek 77 | 568 78 | 568


42 Guess Number Higher or Lower 43 First Bad Version

}
high + low = 1000 0000 0000 0000 0000 0000 0000 0000
= 2147483648 as unsigned 32-bit integer
= -2147483648 as signed 32-bit integer

(high + low) / 2 = 1100 0000 0000 0000 0000 0000 0000 0000 = -1073741824 43 First Bad Version
(high + low) >>> 1 = 0100 0000 0000 0000 0000 0000 0000 0000 = 1073741824

You are a product manager and currently leading a team to develop a new product. Unfortunately, the latest
version of your product fails the quality check. Since each version is developed based on the previous version, all
the versions after a bad version are also bad.
Suppose you have n versions [1, 2, ..., n] and you want to find out the first bad one, which causes all the
following ones to be bad.
You are given an API bool isBadVersion(version) which will return whether version is bad. Implement a
function to find the first bad version. You should minimize the number of calls to the API.

43.1 Java Solution 1 - Recurisve

public int firstBadVersion(int n) {


return helper(1, n);
}

public int helper(int i, int j){


int m = i + (j-i)/2;

if(i>=j)
return i;

if(isBadVersion(m)){
return helper(i, m);
}else{
return helper(m+1, j); //not bad, left --> m+1
}
}

43.2 Java Solution 2 - Iterative

public int firstBadVersion(int n) {


int i = 1, j = n;
while (i < j) {
int m = i + (j-i) / 2;
if (isBadVersion(m)) {
j = m;
} else {
i = m+1;
}
}

if (isBadVersion(i)) {
return i;
}

return j;

Program Creek 79 | 568 80 | 568 Program Creek 81 | 568


44 Search in Rotated Sorted Array

return -1;

int mid = left + (right-left)/2;

if(target == nums[mid])
44 Search in Rotated Sorted Array return mid; 45 Search in Rotated Sorted Array II
if(nums[left] <= nums[mid]){
Suppose a sorted array is rotated at some pivot unknown to you beforehand. (i.e., 0 1 2 4 5 6 7 might become 4 5 if(nums[left]<=target && target<nums[mid]){ Follow up for "Search in Rotated Sorted Array": what if duplicates are allowed? Write a function to determine if
6 7 0 1 2). return binarySearch(nums,left, mid-1, target); a given target is in the array.
You are given a target value to search. If found in the array return its index, otherwise return -1. You may }else{
assume no duplicate exists in the array. return binarySearch(nums, mid+1, right, target);
} 45.1 Java Solution
}else {
44.1 Analysis if(nums[mid]<target&& target<=nums[right]){
public boolean search(int[] nums, int target) {
return binarySearch(nums,mid+1, right, target);
int left=0;
In order to use binary search on the rotated sorted array, we need to determine how to update the left and right }else{
int right=nums.length-1;
pointers. There are two major cases as shown below: return binarySearch(nums, left, mid-1, target);
}
while(left<=right){
}
int mid = (left+right)/2;
}
if(nums[mid]==target)
return true;

if(nums[left]<nums[mid]){
44.3 Java Solution 2 - Iterative
if(nums[left]<=target&& target<nums[mid]){
right=mid-1;
public int search(int[] nums, int target) { }else{
int left = 0; left=mid+1;
int right= nums.length-1; }
}else if(nums[left]>nums[mid]){
while(left<=right){ if(nums[mid]<target&&target<=nums[right]){
int mid = left + (right-left)/2; left=mid+1;
if(target==nums[mid]) }else{
return mid; right=mid-1;
}
if(nums[left]<=nums[mid]){ }else{
if(nums[left]<=target&& target<nums[mid]){ left++;
right=mid-1; }
}else{ }
left=mid+1;
} return false;
}else{ }
if(nums[mid]<target&& target<=nums[right]){
left=mid+1;
Once the two cases are identified, the problem is straightforward to solve. We only need to check if the target }else{
right=mid-1;
element is in the sorted side, and based on that move left or right pointers.
}
}
}
44.2 Java Solution 1- Recusive
return -1;
public int search(int[] nums, int target) { }
return binarySearch(nums, 0, nums.length-1, target);
}

public int binarySearch(int[] nums, int left, int right, int target){
if(left>right)

82 | 568 Program Creek 83 | 568 84 | 568


46 Longest Increasing Subsequence 46 Longest Increasing Subsequence

max[i]=Math.max(max[i], max[j]+1);
}
}
}

46 Longest Increasing Subsequence int result = 0;


for(int i=0; i<max.length; i++){
if(max[i]>result)
Given an unsorted array of integers, find the length of longest increasing subsequence. result = max[i];
For example, given [10, 9, 2, 5, 3, 7, 101, 18], the longest increasing subsequence is [2, 3, 7, 101]. Therefore the }
length is 4. return result;
}

46.1 Java Solution 1 - Naive Or, simplify the code as:

Let max[i] represent the length of the longest increasing subsequence so far. If any element before i is smaller public int lengthOfLIS(int[] nums) {
than nums[i], then max[i] = max(max[i], max[j]+1). if(nums==null || nums.length==0)
Here is an example: return 0;

int[] max = new int[nums.length];


Arrays.fill(max, 1);

int result = 1; public int lengthOfLIS(int[] nums) {


for(int i=0; i<nums.length; i++){ if(nums==null || nums.length==0)
for(int j=0; j<i; j++){ return 0;
if(nums[i]>nums[j]){
max[i]= Math.max(max[i], max[j]+1); ArrayList<Integer> list = new ArrayList<Integer>();

} for(int num: nums){


} if(list.size()==0 || num>list.get(list.size()-1)){
result = Math.max(max[i], result); list.add(num);
} }else{
int i=0;
return result; int j=list.size()-1;
}
while(i<j){
int mid = (i+j)/2;
if(list.get(mid) < num){
46.2 Java Solution 2 - Binary Search i=mid+1;
}else{
We can put the increasing sequence in a list. j=mid;
}
for each num in nums }
if(list.size()==0)
add num to list list.set(j, num);
else if(num > last element in list) }
add num to list }
else
public int lengthOfLIS(int[] nums) { replace the element in the list which is the smallest but bigger than num return list.size();
if(nums==null || nums.length==0) }
return 0;
Note that the problem asks the length of the sequence, not the sequence itself.
int[] max = new int[nums.length];

for(int i=0; i<nums.length; i++){


max[i]=1;
for(int j=0; j<i;j++){
if(nums[i]>nums[j]){

85 | 568 Program Creek 86 | 568 Program Creek 87 | 568


47 Count of Smaller Numbers After Self 47 Count of Smaller Numbers After Self

47.2 Java Solution 2


while(p!=null){
If we want to use binary search, and define a structure like the following: if(value>p.value){
result+=p.count+p.numLeft;
if(p.right==null){
47 Count of Smaller Numbers After Self Node t = new Node(value);
t.count=1;
p.right=t;
You are given an integer array nums and you have to return a new counts array. The counts array has the property return result;
where counts[i] is the number of smaller elements to the right of nums[i]. }else{
Example: p=p.right;
Input: [5,2,6,1] Output: [2,1,1,0] }
}else if(value==p.value){
p.count++;
47.1 Java Solution 1 return result+p.numLeft;
}else{
p.numLeft++;
public List<Integer> countSmaller(int[] nums) {
List<Integer> result = new ArrayList<Integer>(); if(p.left==null){
ArrayList<Integer> sorted = new ArrayList<Integer>(); Node t = new Node(value);
t.count=1;
for(int i=nums.length-1; i>=0; i--){ p.left=t;
if(sorted.isEmpty()){ return result;
sorted.add(nums[i]); }else{
result.add(0); p=p.left;
}else if(nums[i]>sorted.get(sorted.size()-1)){ }
sorted.add(sorted.size(), nums[i]); }
result.add(sorted.size()-1); }
}else{
int l=0; return 0;
int r=sorted.size()-1; }
}
while(l<r){
int m = l + (r-l)/2;
On average, time complexity is O(n*log(n)) and space complexity is O(n).
class Node{
class Solution { Node left;
if(nums[i]>sorted.get(m)){ Node right;
public List<Integer> countSmaller(int[] nums) {
l=m+1;
}else{ int value;
List<Integer> result = new ArrayList<Integer>();
r=m; int count;
if(nums==null || nums.length==0){
} int numLeft;
return result;
} public Node(int value){
}
this.value=value;
sorted.add(r, nums[i]); }
Node root = new Node(nums[nums.length-1]);
result.add(r); }
root.count=1;
}
result.add(0);
}

for(int i=nums.length-2; i>=0; i--){


Collections.reverse(result);
result.add(insertNode(root, nums[i]));
}
return result;
}
Collections.reverse(result);

This solution is simple. However, note that time complexity of adding an element to a list is O(n), because return result;
elements after the insertion position need to be shifted. So the time complexity is O(n2̂(logn)). }

public int insertNode(Node root, int value){


Node p=root;
int result=0;

88 | 568 Program Creek 89 | 568 Program Creek 90 | 568


48 Russian Doll Envelopes

ArrayList<Integer> list = new ArrayList<>();

for(int[] arr: envelopes){


int target = arr[1];

48 Russian Doll Envelopes if(list.isEmpty()||target>list.get(list.size()-1)){ 49 HIndex


list.add(target);
}else{
You have a number of envelopes with widths and heights given as a pair of integers (w, h). One envelope can fit int i=0; Given an array of citations (each citation is a non-negative integer) of a researcher, write a function to compute
into another if and only if both the width and height of one envelope is greater than the width and height of the int j=list.size()-1; the researcher’s h-index. A scientist has index h if h of his/her N papers have at least h citations each, and the
other envelope. other N − h papers have no more than h citations each.
What is the maximum number of envelopes can you Russian doll? (put one inside other) while(i<j){ For example, given citations = [3, 0, 6, 1, 5], which means the researcher has 5 papers in total and each of them
int m = i + (j-i)/2; had received 3, 0, 6, 1, 5 citations respectively. Since the researcher has 3 papers with at least 3 citations each and
if(list.get(m)>=target){ the remaining two with no more than 3 citations each, his h-index is 3.
48.1 Java Solution 1 - Naive j = m;
}else{
i = m+1; 49.1 Java Solution 1
public int maxEnvelopes(int[][] envelopes) { }
if(envelopes==null||envelopes.length==0) }
return 0;
list.set(j, target);
Arrays.sort(envelopes, new Comparator<int[]>(){ }
public int compare(int[] a, int[] b){ }
if(a[0]!=b[0]){
return a[0]-b[0]; return list.size();
}else{ }
return a[1]-b[1];
} Time complexity is O(n*log(n)) and we need O(n) of space for the list.
}
});
int max=1;
int[] arr = new int[envelopes.length];
for(int i=0; i<envelopes.length; i++){
arr[i]=1;
for(int j=i-1; j>=0; j--){
if(envelopes[i][0]>envelopes[j][0]&&envelopes[i][1]>envelopes[j][1]){
arr[i]=Math.max(arr[i], arr[j]+1);
}
}
max = Math.max(max, arr[i]);
}

return max;
} public int hIndex(int[] citations) {
Arrays.sort(citations);

int result = 0;
48.2 Java Solution 2 - Binary Search for(int i=citations.length-1; i>=0; i--){
int cnt = citations.length-i;
We can sort the envelopes by height in ascending order and width in descending order. Then look at the width if(citations[i]>=cnt){
result = cnt;
and find the longest increasing subsequence. This problem is then converted to the problem of finding Longeset
}else{
Increasing Subsequence.
break;
public int maxEnvelopes(int[][] envelopes) { }
Comparator c = Comparator.comparing((int[] arr) -> arr[0]) }
.thenComparing((int[] arr) -> arr[1], Comparator.reverseOrder());
Arrays.sort(envelopes, c); return result;
}

91 | 568 Program Creek 92 | 568 93 | 568


49 HIndex

49.2 Java Solution 2


We can also put the citations in a counting sort array, then iterate over the counter array.

public int hIndex(int[] citations) {


int len = citations.length; 50 HIndex II 51 Valid Anagram
int[] counter = new int[len+1];

for(int c: citations){ Follow up for H-Index: What if the citations array is sorted in ascending order? Could you optimize your Given two strings s and t, write a function to determine if t is an anagram of s.
counter[Math.min(len,c)]++; algorithm?
}
51.1 Java Solution 1
int k=len; 50.1 Java Solution
for(int s=counter[len]; k > s; s += counter[k]){ Assuming the string contains only lowercase alphabets, here is a simple solution.
k--; Given the array is sorted, we should use binary search.
} public boolean isAnagram(String s, String t) {
int hIndex(int[] citations) { if(s==null || t==null)
return k; int len = citations.length; return false;
}
if (len == 0) { if(s.length()!=t.length())
return 0; return false;
}
int[] arr = new int[26];
if (len == 1) { for(int i=0; i<s.length(); i++){
if (citations[0] == 0) { arr[s.charAt(i)-’a’]++;
return 0; arr[t.charAt(i)-’a’]--;
} else { }
return 1;
} for(int i: arr){
} if(i!=0)
return false;
int i = 0; }
int j = len - 1;
while (i < j) { return true;
int m = i + (j - i + 1) / 2; }
if (citations[m] > len - m) {
j = m - 1;
} else {
i = m; 51.2 Java Solution 2
}
} If the inputs contain unicode characters, an array with length of 26 is not enough.

if (citations[j] > len - j) { public boolean isAnagram(String s, String t) {


return len; if(s.length()!=t.length())
} return false;

if (citations[j] == len - j) { HashMap<Character, Integer> map = new HashMap<Character, Integer>();


return len - j;
} else { for(int i=0; i<s.length(); i++){
return len - j - 1; char c1 = s.charAt(i);
} if(map.containsKey(c1)){
} map.put(c1, map.get(c1)+1);
}else{
map.put(c1,1);
}
}

for(int i=0; i<s.length(); i++){

Program Creek 94 | 568 95 | 568 96 | 568


51 Valid Anagram 52 Group Shifted Strings

char c2 = t.charAt(i); result.addAll(map.values());


if(map.containsKey(c2)){
if(map.get(c2)==1){ return result;
map.remove(c2); }
}else{
map.put(c2, map.get(c2)-1); 52 Group Shifted Strings
}
}else{
return false; Given a string, we can "shift" each of its letter to its successive letter, for example: "abc" ->"bcd". We can keep
} "shifting" which forms the sequence: "abc" ->"bcd" ->... ->"xyz".
} Given a list of strings which contains only lowercase alphabets, group all strings that belong to the same shifting
sequence, return:
if(map.size()>0)
return false; [
["abc","bcd","xyz"],
return true; ["az","ba"],
} ["acef"],
["a","z"]
]

52.1 Java Solution

public List<List<String>> groupStrings(String[] strings) {


List<List<String>> result = new ArrayList<List<String>>();
HashMap<String, ArrayList<String>> map
= new HashMap<String, ArrayList<String>>();

for(String s: strings){
char[] arr = s.toCharArray();
if(arr.length>0){
int diff = arr[0]-’a’;
for(int i=0; i<arr.length; i++){
if(arr[i]-diff<’a’){
arr[i] = (char) (arr[i]-diff+26);
}else{
arr[i] = (char) (arr[i]-diff);
}

}
}

String ns = new String(arr);


if(map.containsKey(ns)){
map.get(ns).add(s);
}else{
ArrayList<String> al = new ArrayList<String>();
al.add(s);
map.put(ns, al);
}
}

for(Map.Entry<String, ArrayList<String>> entry: map.entrySet()){


Collections.sort(entry.getValue());
}

Program Creek 97 | 568 98 | 568 Program Creek 99 | 568


53 Palindrome Pairs

}
}

return result;
}
53 Palindrome Pairs 54 Line Reflection
public boolean isPalindrome(String s){
int i=0;
Given a list of unique words. Find all pairs of distinct indices (i, j) in the given list, so that the concatenation of int j=s.length()-1; Given n points on a 2D plane, find if there is such a line parallel to y-axis that reflects the given points.
the two words, i.e. words[i] + words[j] is a palindrome. Example 1: Given points = [[1,1],[-1,1]], return true.
Example 1: Given words = ["bat", "tab", "cat"] Return [[0, 1], [1, 0]] The palindromes are ["battab", "tabbat"] while(i<=j){ Example 2: Given points = [[1,1],[-1,-1]], return false.
if(s.charAt(i)!=s.charAt(j)){ Follow up: Could you do better than O(n2)?
return false;
53.1 Java Solution }
i++; 54.1 Java Solution
j--;
public List<List<Integer>> palindromePairs(String[] words) { } For this problem, we first find the smallest and largest x-value for all points and get the line’s x-axis is (minX +
List<List<Integer>> result = new ArrayList<>();
maxX) / 2, then for each point, check if each point has a reflection points in the set.
if(words == null || words.length < 2){ return true;
return result; } public boolean isReflected(int[][] points) {
} if(points==null || points.length<2)
Time complexity is O(n*k2̂), where n is the number of words and k is the average length of each word. return true;
HashMap<String, Integer> map = new HashMap<>();
for(int i=0; i<words.length; i++){ HashMap<Integer, HashSet<Integer>> map = new HashMap<Integer, HashSet<Integer>>();
map.put(words[i], i);
} int min=Integer.MAX_VALUE;
int max=Integer.MIN_VALUE;
for(int i=0; i<words.length; i++){
String s = words[i]; for(int[] arr: points){
min = Math.min(min, arr[0]);
for(int k=0; k<=s.length(); k++){ max = Math.max(max, arr[0]);
String left = s.substring(0, k); HashSet<Integer> set = map.get(arr[0]);
String right= s.substring(k); if(set==null){
set = new HashSet<Integer>();
//if left part is palindrome, find reversed right part map.put(arr[0], set);
if(isPalindrome(left)){ }
String reversedRight = new StringBuilder(right).reverse().toString();
if(map.containsKey(reversedRight) && map.get(reversedRight) != i){ set.add(arr[1]);
ArrayList<Integer> l = new ArrayList<>();
l.add(map.get(reversedRight)); }
l.add(i);
result.add(l); int y = min+max;
}
} for(int[] arr: points){
int left = arr[0];
//if right part is a palindrome, find reversed left part int right = y-left;
if(isPalindrome(right)){ if(map.get(right)==null || !map.get(right).contains(arr[1])){
String reversedLeft = new StringBuilder(left).reverse().toString(); return false;
if(map.containsKey(reversedLeft) }
&& map.get(reversedLeft) != i }
&& right.length() != 0){
//make sure right is not "", already handled in the if above return true;
ArrayList<Integer> l = new ArrayList<>(); }
l.add(i);
l.add(map.get(reversedLeft));
result.add(l);
}
}

100 | 568 Program Creek 101 | 568 102 | 568


55 Isomorphic Strings 56 Two Sum 57 Maximum Size Subarray Sum Equals k
Given two strings s and t, determine if they are isomorphic. Two strings are isomorphic if the characters in s can Given an array of integers, find two numbers such that they add up to a specific target number. Given an array nums and a target value k, find the maximum length of a subarray that sums to k. If there isn’t
be replaced to get t. The function twoSum should return indices of the two numbers such that they add up to the target, where one, return 0 instead.
For example,"egg" and "add" are isomorphic, "foo" and "bar" are not. index1 must be less than index2. Please note that your returned answers (both index1 and index2) are not Note: The sum of the entire nums array is guaranteed to fit within the 32-bit signed integer range.
zero-based. Example 1: Given nums = [1, -1, 5, -2, 3], k = 3, return 4. (because the subarray [1, -1, 5, -2] sums to 3 and is the
For example: longest)
55.1 Analysis
Input: numbers={2, 7, 11, 15}, target=9
We can define a map which tracks the char-char mappings. If a value is already mapped, it can not be mapped Output: index1=0, index2=1 57.1 Java Solution
again.
This problem is similar to Maximum Sum of SubArray Close to K.

55.2 Java Solution 56.1 Java Solution


The optimal solution to solve this problem is using a HashMap. For each element of the array, (target-nums[i])
public boolean isIsomorphic(String s, String t) { and the index are stored in the HashMap.
if(s.length()!=t.length()){
return false; public int[] twoSum(int[] nums, int target) {
} if(nums==null || nums.length<2)
return new int[]{0,0};
HashMap<Character, Character> map1 = new HashMap<>();
HashMap<Character, Character> map2 = new HashMap<>(); HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
for(int i=0; i<nums.length; i++){
for(int i=0; i<s.length(); i++){ if(map.containsKey(nums[i])){
char c1 = s.charAt(i); return new int[]{map.get(nums[i]), i};
char c2 = t.charAt(i); }else{
map.put(target-nums[i], i);
if(map1.containsKey(c1)){ }
if(c2!=map1.get(c1)){ }
return false;
} return new int[]{0,0};
}else{ }
if(map2.containsKey(c2)){
return false; Time complexity is O(n).
}

map1.put(c1, c2);
map2.put(c2, c1);
}
}

return true;
public int maxSubArrayLen(int[] nums, int k) {
}
HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();

Time complexity is O(n) and space complexity is O(n), where n is the length of the input string. int max = 0;

int sum=0;
for(int i=0; i<nums.length; i++){
sum += nums[i];

if(sum==k){

103 | 568 104 | 568 105 | 568


57 Maximum Size Subarray Sum Equals k

max = Math.max(max, i+1);


}

int diff = sum-k;

if(map.containsKey(diff)){ 58 Subarray Sum Equals K 59 Maximum Subarray


max = Math.max(max, i-map.get(diff));
}
Given an array of integers and an integer k, find the total number of continuous subarrays whose sum equals to Find the contiguous subarray within an array (containing at least one number) which has the largest sum.
if(!map.containsKey(sum)){ k. For example, given the array [−2,1,−3,4,−1,2,1,−5,4], the contiguous subarray [4,−1,2,1] has the largest sum =
map.put(sum, i); Example 1: 6.
} Input:nums = [1,1,1], k = 2 Output: 2
} Note that empty array is not considered as a subarray.
59.1 Java Solution 1 - DP
return max; 58.1 Java Solution The easiest way to formulate the solution of this problem is using DP. Let f(n) be the maximum subarray for an
} array with n elements. We need to find the subproblem and the relation.
The sum problems can often be solved by using a hash map efficiently.
f(n) = { f(n-1)>0 ? f(n-1) : 0 } + nums[n-1]
public int subarraySum(int[] nums, int k) {
HashMap<Integer, Integer> map = new HashMap<>(); f(0) = 0
map.put(0, 1); f(1) = nums[0]

int count = 0;
int sum = 0;

//e.g., 1 1 2 1 1
for(int i=0; i<nums.length; i++){
sum += nums[i];
int n = map.getOrDefault(sum-k, 0);
count += n;

map.put(sum, map.getOrDefault(sum,0)+1);
}

return count;
}

The changing condition for dynamic programming is "We should ignore the sum of the previous n-1 elements
if nth element is greater than the sum."

public class Solution {


public int maxSubArray(int[] A) {
int max = A[0];
int[] sum = new int[A.length];
sum[0] = A[0];

Program Creek 106 | 568 107 | 568 108 | 568


59 Maximum Subarray 59 Maximum Subarray

int result = Integer.MIN_VALUE;


for (int i = 1; i < A.length; i++) {
sum[i] = Math.max(A[i], sum[i - 1] + A[i]); for(int i=0; i<nums.length; i++){
max = Math.max(max, sum[i]); sum = sum+nums[i];
} result = Math.max(result, sum-pre.peek());
pre.offer(sum); 60 Maximum Product Subarray
return max; }
}
} return result; Find the contiguous subarray within an array (containing at least one number) which has the largest product.
} For example, given the array [2,3,-2,4], the contiguous subarray [2,3] has the largest product = 6.
The time complexity and space complexity are the same O(n). However, we can improve the space complexity
and make it to be O(1). Time complexity is O(nLogn) and space complexity is O(n).
60.1 Java Solution - Dynamic Programming
public int maxSubArray(int[] nums) {
//[-2,1,-3,4,-1,2,1,-5,4], This is similar to maximum subarray. Instead of sum, the sign of number affect the product value.
int result = nums[0]; When iterating the array, each element has two possibilities: positive number or negative number. We need to
int sum = nums[0]; track a minimum value, so that when a negative number is given, it can also find the maximum value. We define
for(int i=1; i<nums.length; i++){ two local variables, one tracks the maximum and the other tracks the minimum.
if(sum<=0){
sum = nums[i]; public int maxProduct(int[] nums) {
}else{ int[] max = new int[nums.length];
sum += nums[i]; int[] min = new int[nums.length];
}
result = Math.max(result, sum); max[0] = min[0] = nums[0];
} int result = nums[0];

return result; for(int i=1; i<nums.length; i++){


} if(nums[i]>0){
max[i]=Math.max(nums[i], max[i-1]*nums[i]);
min[i]=Math.min(nums[i], min[i-1]*nums[i]);
}else{
59.2 Java Solution 2 - Using Sum Diff max[i]=Math.max(nums[i], min[i-1]*nums[i]);
min[i]=Math.min(nums[i], max[i-1]*nums[i]);
Like other array sum related problems, the target sum k can be expressed as sum-sum’: }

result = Math.max(result, max[i]);


}

return result;
}

Time is O(n).

public int maxSubArray(int[] nums) {


if(nums==null || nums.length==0){
return 0;
}

PriorityQueue<Integer> pre= new PriorityQueue<>();


pre.offer(0);

int sum = 0;

Program Creek 109 | 568 Program Creek 110 | 568 111 | 568
61 Longest Substring Without Repeating Characters

61.3 Java Solution 2 - HashSet


61 Longest Substring Without Repeating 62 Longest Substring with At Most K Distinct
Using a HashSet can simplify the code a lot.
Characters Characters
/*
pwwkew
Given a string, find the length of the longest substring without repeating characters. For example, the longest i | This is a problem asked by Google.
substring without repeating letters for "abcabcbb" is "abc", which the length is 3. For "bbbbb" the longest substring j | Given a string, find the longest substring that contains only two unique characters. For example, given "abcbbb-
is "b", with the length of 1. bcccbdddadacb", the longest substring that contains 2 unique character is "bcbbbbcccb".
i |
j |
61.1 Analysis 62.1 Longest Substring Which Contains 2 Unique Characters
i |
The basic idea to solve this problem is using an extra data structure to track the unique characters in a sliding j |
In this solution, a hashmap is used to track the unique elements in the map. When a third character is added to
window. Both an array and a hash set work for this purpose. the map, the left pointer needs to move right.
*/
You can use "abac" to walk through this solution.
public int lengthOfLongestSubstring(String s) {
if(s==null||s.length()==0){
61.2 Java Solution 1 public int lengthOfLongestSubstringTwoDistinct(String s) {
return 0;
int max=0;
}
The first solution is like the problem of "determine if a string has all unique characters" in CC 150. We can use a HashMap<Character,Integer> map = new HashMap<Character, Integer>();
flag array to track the existing characters for the longest substring without repeating characters. int start=0;
HashSet<Character> set = new HashSet<>();
int result = 1;
public int lengthOfLongestSubstring(String s) { for(int i=0; i<s.length(); i++){
int i=0;
if(s==null) char c = s.charAt(i);
for(int j=0; j<s.length(); j++){
return 0; if(map.containsKey(c)){
char c = s.charAt(j);
boolean[] flag = new boolean[256]; map.put(c, map.get(c)+1);
if(!set.contains(c)){
}else{
set.add(c);
int result = 0; map.put(c,1);
result = Math.max(result, set.size());
int start = 0; }
}else{
char[] arr = s.toCharArray();
while(i<j){
if(map.size()>2){
if(s.charAt(i)==c){
for (int i = 0; i < arr.length; i++) { max = Math.max(max, i-start);
i++;
char current = arr[i];
break;
if (flag[current]) { while(map.size()>2){
}
result = Math.max(result, i - start); char t = s.charAt(start);
// the loop update the new start point int count = map.get(t);
set.remove(s.charAt(i));
// and reset flag array if(count>1){
i++;
// for example, abccab, when it comes to 2nd c, map.put(t, count-1);
}
// it update start from 0 to 3, reset flag for a,b }else{
}
for (int k = start; k < i; k++) { map.remove(t);
}
if (arr[k] == current) { }
start = k + 1; start++;
return result;
break; }
}
} }
flag[arr[k]] = false; }
}
} else { max = Math.max(max, s.length()-start);
flag[current] = true;
} return max;
} }

result = Math.max(arr.length - start, result); Now if this question is extended to be "the longest substring that contains k unique characters", what should
we do?
return result;

112 | 568 Program Creek 113 | 568 114 | 568


62 Longest Substring with At Most K Distinct Characters 63 Substring with Concatenation of All Words

62.2 Solution for K Unique Characters while(currentMap.get(sub)>map.get(sub)){


String left = s.substring(start, start+len);
The following solution is corrected. Given "abcadcacacaca" and 3, it returns "cadcacacaca". currentMap.put(left, currentMap.get(left)-1);

public int lengthOfLongestSubstringKDistinct(String s, int k) { count--;


int result = 0; 63 Substring with Concatenation of All Words start = start + len;
int i=0; }
HashMap<Character, Integer> map = new HashMap<Character, Integer>();
You are given a string, s, and a list of words, words, that are all of the same length. Find all starting indices
for(int j=0; j<s.length(); j++){ of substring(s) in s that is a concatenation of each word in words exactly once and without any intervening if(count==words.length){
char c = s.charAt(j); characters. result.add(start); //add to result
if(map.containsKey(c)){ For example, given: s="barfoothefoobarman" & words=["foo", "bar"], return [0,9].
map.put(c, map.get(c)+1); //shift right and reset currentMap, count & start point
}else{ String left = s.substring(start, start+len);
map.put(c, 1); 63.1 Analysis currentMap.put(left, currentMap.get(left)-1);
} count--;
This problem is similar (almost the same) to Longest Substring Which Contains 2 Unique Characters. start = start + len;
if(map.size()<=k){ }
Since each word in the dictionary has the same length, each of them can be treated as a single character.
result = Math.max(result, j-i+1); }else{
}else{ currentMap.clear();
while(map.size()>k){
63.2 Java Solution start = i+len;
char l = s.charAt(i); count = 0;
int count = map.get(l); }
if(count==1){ public List<Integer> findSubstring(String s, String[] words) { }
map.remove(l); ArrayList<Integer> result = new ArrayList<Integer>(); }
}else{ if(s==null||s.length()==0||words==null||words.length==0){
map.put(l, map.get(l)-1); return result; return result;
} } }
i++;
} //frequency of words
} HashMap<String, Integer> map = new HashMap<String, Integer>();
for(String w: words){
} if(map.containsKey(w)){
map.put(w, map.get(w)+1);
return result; }else{
} map.put(w, 1);
}
Time is O(n). }

int len = words[0].length();

for(int j=0; j<len; j++){


HashMap<String, Integer> currentMap = new HashMap<String, Integer>();
int start = j;//start index of start
int count = 0;//count totoal qualified words so far

for(int i=j; i<=s.length()-len; i=i+len){


String sub = s.substring(i, i+len);
if(map.containsKey(sub)){
//set frequency in current map
if(currentMap.containsKey(sub)){
currentMap.put(sub, currentMap.get(sub)+1);
}else{
currentMap.put(sub, 1);
}

count++;

Program Creek 115 | 568 116 | 568 Program Creek 117 | 568
64 Minimum Window Substring

}
}
}

return result;
64 Minimum Window Substring } 65 Longest Substring with At Least K Repeating
Given a string S and a string T, find the minimum window in S which will contain all the characters in T in
Characters
complexity O(n).
For example, S = "ADOBECODEBANC", T = "ABC", Minimum window is "BANC". Find the length of the longest substring T of a given string (consists of lowercase letters only) such that every
character in T appears no less than k times.
Example 1:
64.1 Java Solution
Input:
s = "aaabb", k = 3
public String minWindow(String s, String t) {
HashMap<Character, Integer> goal = new HashMap<>(); Output:
int goalSize = t.length(); 3
int minLen = Integer.MAX_VALUE; The longest substring is "aaa", as ’a’ is repeated 3 times.
String result = "";

//target dictionary
for(int k=0; k<t.length(); k++){
65.1 Java Solution
goal.put(t.charAt(k), goal.getOrDefault(t.charAt(k), 0)+1);
}
This problem can be solved using DFS. When all chars in the input string occurs >=k, return the length. But we
first need to split the input string by using the characters whose occurrence <k.
int i=0;
int total=0; public int longestSubstring(String s, int k) {
HashMap<Character, Integer> map = new HashMap<>(); HashMap<Character, Integer> counter = new HashMap<Character, Integer>();
for(int j=0; j<s.length(); j++){
char c = s.charAt(j); for(int i=0; i<s.length(); i++){
if(!goal.containsKey(c)){
continue; char c = s.charAt(i);
} if(counter.containsKey(c)){
counter.put(c, counter.get(c)+1);
//if c is a target character in the goal, and count is < goal, increase the total }else{
int count = map.getOrDefault(c, 0); counter.put(c, 1);
if(count<goal.get(c)){ }
total++;
} }

map.put(c, count+1); HashSet<Character> splitSet = new HashSet<Character>();


for(char c: counter.keySet()){
//when total reaches the goal, trim from left until no more chars can be trimmed. if(counter.get(c)<k){
if(total==goalSize){ splitSet.add(c);
while(!goal.containsKey(s.charAt(i)) || map.get(s.charAt(i))>goal.get(s.charAt(i))){ }
char pc = s.charAt(i); }
if(goal.containsKey(pc) && map.get(pc)>goal.get(pc)){
map.put(pc, map.get(pc)-1); if(splitSet.isEmpty()){
} return s.length();
}
i++;
} int max = 0;
int i=0, j=0;
if(minLen>j-i+1){ while(j<s.length()){
minLen = j-i+1; char c = s.charAt(j);
result = s.substring(i, j+1); if(splitSet.contains(c)){

118 | 568 Program Creek 119 | 568 120 | 568


65 Longest Substring with At Least K Repeating Characters 66 Permutation in String

if(j!=i){ }
max = Math.max(max, longestSubstring(s.substring(i, j), k));
}
i=j+1;
}
j++; 66 Permutation in String
}

if(i!=j) Given two strings s1 and s2, write a function to return true if s2 contains the permutation of s1. In other words,
max = Math.max(max, longestSubstring(s.substring(i, j), k)); one of the first string’s permutations is the substring of the second string.
For example:
return max;
} Input: s1 = "ab" s2 = "eidbaooo"
Output: True
Explanation: s2 contains one permutation of s1 ("ba").

66.1 Java Solution

public boolean checkInclusion(String s1, String s2) {


HashMap<Character, Integer> dict = new HashMap<>();
for (int i = 0; i < s1.length(); i++) {
int feq = dict.getOrDefault(s1.charAt(i), 0);
dict.put(s1.charAt(i), feq + 1);
}

HashMap<Character, Integer> temp = new HashMap<>();


int i = 0;
for (int j = 0; j < s2.length(); j++) {
if (!dict.containsKey(s2.charAt(j))) {
i = j + 1;
temp.clear(); //clear counter
continue;
}

int count = temp.getOrDefault(s2.charAt(j), 0);


if (count == 0 || count < dict.get(s2.charAt(j))) {
temp.put(s2.charAt(j), count + 1);

if (j - i + 1 == s1.length()) {
return true;
}
} else {
while (i < j) {
if (s2.charAt(i) == s2.charAt(j)) {
i++;
break;
}

temp.put(s2.charAt(i), temp.get(s2.charAt(i)) - 1);


i++;
}
}
}

return false;

Program Creek 121 | 568 122 | 568 Program Creek 123 | 568
67 Longest Consecutive Sequence

67.2 Java Solution 2


We can also project the arrays to a new array with length to be the largest element in the array. Then iterate over
the array and get the longest consecutive sequence. If the largest number is very large, then the time complexity
would be bad.
67 Longest Consecutive Sequence 68 Majority Element
Given an unsorted array of integers, find the length of the longest consecutive elements sequence. Given an array of size n, find the majority element. The majority element is the element that appears more than
For example, given [100, 4, 200, 1, 3, 2], the longest consecutive elements sequence should be [1, 2, 3, 4]. Its ⌊ n/2 ⌋ times. (assume that the array is non-empty and the majority element always exist in the array.)
length is 4.
Your algorithm should run in O(n) complexity.
68.1 Java Solution 1 - Sorting

67.1 Java Solution 1 Assuming the majority exists and since the majority always takes more than half of space, the middle element is
guaranteed to be the majority. Sorting array takes O(nlog(n)). So the time complexity of this solution is nlog(n).
Because it requires O(n) complexity, we can not solve the problem by sorting the array first. Sorting takes at least
public int majorityElement(int[] num) {
O(nlogn) time.
if (num.length == 1) {
We can use a HashSet to add and remove elements. HashSet is implemented by using a hash table. Elements
return num[0];
are not ordered. The add, remove and contains methods have constant time complexity O(1). }

public static int longestConsecutive(int[] num) {


Arrays.sort(num);
// if array is empty, return 0
return num[num.length / 2];
if (num.length == 0) {
}
return 0;
}

Set<Integer> set = new HashSet<Integer>();


int max = 1; 68.2 Java Solution 2 - Majority Vote Algorithm

for (int e : num) This problem can be solved in time of O(n) with constant space complexity. The basic idea is that the majority
set.add(e); element can negate all other element’s count.

for (int e : num) {


int left = e - 1;
int right = e + 1;
int count = 1;

while (set.contains(left)) {
count++;
set.remove(left);
left--;
}

while (set.contains(right)) { public int majorityElement(int[] nums) {


count++; int result = 0, count = 0;
set.remove(right);
right++; for(int i = 0; i<nums.length; i++ ) {
} if(count == 0){
result = nums[ i ];
max = Math.max(count, max); count = 1;
} }else if(result == nums[i]){
count++;
return max; }else{
} count--;
}
}

124 | 568 Program Creek 125 | 568 126 | 568


68 Majority Element

return result;
}

69 Majority Element II 70 Increasing Triplet Subsequence


Given an integer array of size n, find all elements that appear more than ⌊ n/3 ⌋ times. The algorithm should run Given an unsorted array return whether an increasing subsequence of length 3 exists or not in the array.
in linear time and in O(1) space. Examples: Given [1, 2, 3, 4, 5], return true.
Given [5, 4, 3, 2, 1], return false.

69.1 Java Solution


70.1 Analysis
This problem is similar to Majority Element I. Time = O(n) and Space = O(1).
This problem can be formalized as finding a sequence x, y and z, such that x <y <z .
public List<Integer> majorityElement(int[] nums) {
List<Integer> result = new ArrayList<Integer>();

Integer n1=null, n2=null;


int c1=0, c2=0;

for(int i: nums){
if(n1!=null && i==n1.intValue()){
c1++;
}else if(n2!=null && i==n2.intValue()){
c2++;
}else if(c1==0){
c1=1;
n1=i;
}else if(c2==0){
c2=1;
n2=i;
}else{
c1--;
c2--;
}
}

c1=c2=0;
70.2 Java Solution

for(int i: nums){ public boolean increasingTriplet(int[] nums) {


if(i==n1.intValue()){ int x = Integer.MAX_VALUE;
c1++; int y = Integer.MAX_VALUE;
}else if(i==n2.intValue()){
c2++; for (int i = 0; i < nums.length; i++) {
} int z = nums[i];
}
if (x >= z) {
if(c1>nums.length/3) x = z;// update x to be a smaller value
result.add(n1); } else if (y >= z) {
if(c2>nums.length/3) y = z; // update y to be a smaller value
result.add(n2); } else {
return true;
return result; }
} }

return false;

Program Creek 127 | 568 128 | 568 129 | 568


70 Increasing Triplet Subsequence

71 Find the Second Largest Number in an Array 72 Word Ladder


Given two words (start and end), and a dictionary, find the length of shortest transformation sequence from start
71.1 Problem to end, such that only one letter can be changed at a time and each intermediate word must exist in the dictionary.
Given an integer array, find the second largest number in the array. For example, given:

start = "hit"
end = "cog"
71.2 Solution dict = ["hot","dot","dog","lot","log"]

The optimal time is linear to the length of the array N. We can iterate over the array, whenever the largest elements
One shortest transformation is "hit" ->"hot" ->"dot" ->"dog" ->"cog", the program should return its length 5.
get updated, its current value becomes the second largest.

public static int getSecondLargest(int[] arr){


int first = Integer.MIN_VALUE;
72.1 Java Solution
int second = Integer.MIN_VALUE;
This is a search problem, and breath-first search guarantees the optimal solution.
for(int i=0; i<arr.length; i++){
if(arr[i]>first){
second=first;
first=arr[i];
}
}

return second;
}

class WordNode{
String word;
int numSteps;

public WordNode(String word, int numSteps){


this.word = word;
this.numSteps = numSteps;
}
}

public class Solution {


public int ladderLength(String beginWord, String endWord, Set<String> wordDict) {
LinkedList<WordNode> queue = new LinkedList<WordNode>();
queue.add(new WordNode(beginWord, 1));

wordDict.add(endWord);

while(!queue.isEmpty()){
WordNode top = queue.remove();
String word = top.word;

if(word.equals(endWord)){

Program Creek 130 | 568 131 | 568 132 | 568


72 Word Ladder 73 Word Ladder II

return top.numSteps; List<String> aResult = new ArrayList<>();


} aResult.add(endWord);
Node p = top;
char[] arr = word.toCharArray(); while(p!=null){
for(int i=0; i<arr.length; i++){ aResult.add(p.word);
for(char c=’a’; c<=’z’; c++){ 73 Word Ladder II p = p.prev;
char temp = arr[i]; }
if(arr[i]!=c){
arr[i]=c; Given two words (start and end), and a dictionary, find all shortest transformation sequence(s) from start to end, Collections.reverse(aResult);
} such that: 1) Only one letter can be changed at a time, 2) Each intermediate word must exist in the dictionary. result.add(aResult);
For example, given: start = "hit", end = "cog", and dict = ["hot","dot","dog","lot","log"], return:
String newWord = new String(arr); //stop if get shorter result
if(wordDict.contains(newWord)){ [ if(top.depth<=minLen){
queue.add(new WordNode(newWord, top.numSteps+1)); ["hit","hot","dot","dog","cog"], minLen=top.depth;
wordDict.remove(newWord); ["hit","hot","lot","log","cog"] }else{
} ] return result;
}
arr[i]=temp; }
}
} 73.1 Java Solution if(unvisited.contains(t)){
} Node n=new Node(t,top.depth+1,top);
This is an extension of Word Ladder. The idea is the same. To track the actual ladder, we need to add a pointer queue.offer(n);
return 0; that points to the previous node in the WordNode class. In addition, the used word can not directly removed unvisited.remove(t);
} from the dictionary. The used word is only removed when steps change. }
} }
class Solution { }
}
public List<List<String>> findLadders(String beginWord, String endWord, List<String> wordList) {
List<List<String>> result = new ArrayList<List<String>>(); return result;
}
HashSet<String> unvisited = new HashSet<>(); }
unvisited.addAll(wordList);
class Node{
LinkedList<Node> queue = new LinkedList<>(); public String word;
Node node = new Node(beginWord,0,null); public int depth;
queue.offer(node); public Node prev;

int minLen = Integer.MAX_VALUE; public Node(String word, int depth, Node prev){
while(!queue.isEmpty()){ this.word=word;
Node top = queue.poll(); this.depth=depth;
this.prev=prev;
//top if have shorter result already }
if(result.size()>0 && top.depth>minLen){ }
return result;
}

for(int i=0; i<top.word.length(); i++){


char c = top.word.charAt(i);
char[] arr = top.word.toCharArray();
for(char j=’z’; j>=’a’; j--){
if(j==c){
continue;
}
arr[i]=j;
String t = new String(arr);

if(t.equals(endWord)){
//add to result

Program Creek 133 | 568 134 | 568 Program Creek 135 | 568
74 Top K Frequent Elements 74 Top K Frequent Elements

return result; 74.3 Java Solution 3 - A Regular Counter (Deprecated)


}
} We can solve this problem by using a regular counter, and then sort the counter by value.

public class Solution {


74 Top K Frequent Elements public List<Integer> topKFrequent(int[] nums, int k) {
74.2 Java Solution 2 - Bucket Sort List<Integer> result = new ArrayList<Integer>();

Given a non-empty array of integers, return the k most frequent elements. Time is O(n). HashMap<Integer, Integer> counter = new HashMap<Integer, Integer>();

public List<Integer> topKFrequent(int[] nums, int k) { for(int i: nums){


74.1 Java Solution 1 - Heap //count the frequency for each element if(counter.containsKey(i)){
HashMap<Integer, Integer> map = new HashMap<Integer, Integer>(); counter.put(i, counter.get(i)+1);
Time complexity is O(n*log(k)). Note that heap is often used to reduce time complexity from n*log(n) (see solution for(int num: nums){ }else{
3) to n*log(k). if(map.containsKey(num)){ counter.put(i, 1);
map.put(num, map.get(num)+1); }
class Pair{ }else{ }
int num; map.put(num, 1);
int count; } TreeMap<Integer, Integer> sortedMap = new TreeMap<Integer, Integer>(new ValueComparator(counter));
public Pair(int num, int count){ } sortedMap.putAll(counter);
this.num=num;
this.count=count; //get the max frequency int i=0;
} int max = 0; for(Map.Entry<Integer, Integer> entry: sortedMap.entrySet()){
} for(Map.Entry<Integer, Integer> entry: map.entrySet()){ result.add(entry.getKey());
max = Math.max(max, entry.getValue()); i++;
class Solution { } if(i==k)
public List<Integer> topKFrequent(int[] nums, int k) { break;
//count the frequency for each element //initialize an array of ArrayList. index is frequency, value is list of numbers }
HashMap<Integer, Integer> map = new HashMap<>(); ArrayList<Integer>[] arr = (ArrayList<Integer>[]) new ArrayList[max+1];
for(int num: nums){ for(int i=1; i<=max; i++){ return result;
if(map.containsKey(num)){ arr[i]=new ArrayList<Integer>(); }
map.put(num, map.get(num)+1); } }
}else{
map.put(num, 1); for(Map.Entry<Integer, Integer> entry: map.entrySet()){ class ValueComparator implements Comparator<Integer>{
} int count = entry.getValue(); HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
} int number = entry.getKey();
arr[count].add(number); public ValueComparator(HashMap<Integer, Integer> m){
// create a min heap } map.putAll(m);
PriorityQueue<Pair> queue = new PriorityQueue<>(Comparator.comparing(Pair->Pair.count)); }
List<Integer> result = new ArrayList<Integer>();
//maintain a heap of size k. public int compare(Integer i1, Integer i2){
for(Map.Entry<Integer, Integer> entry: map.entrySet()){ //add most frequent numbers to result int diff = map.get(i2)-map.get(i1);
Pair p = new Pair(entry.getKey(), entry.getValue()); for(int j=max; j>=1; j--){
queue.offer(p); if(arr[j].size()>0){ if(diff==0){
if(queue.size()>k){ for(int a: arr[j]){ return 1;
queue.poll(); result.add(a); }else{
} //if size==k, stop return diff;
} if(result.size()==k){ }
break; }
//get all elements from the heap } }
List<Integer> result = new ArrayList<>(); }
while(queue.size()>0){ }
result.add(queue.poll().num); }
}
return result;
//reverse the order }
Collections.reverse(result);

136 | 568 Program Creek 137 | 568 Program Creek 138 | 568
75 Meeting Rooms II

75 Meeting Rooms II 76 Meeting Rooms


Given an array of meeting time intervals consisting of start and end times [[s1,e1],[s2,e2],...] find the minimum Given an array of meeting time intervals consisting of start and end times [s1, e1], [s2, e2], ... , determine if a
number of conference rooms required. person could attend all meetings.
For example, Given [ [0, 30], [5, 10], [15, 20] ], return false.

75.1 Java Solution


76.1 Java Solution
The basic idea of the solution is that we sequentially assign meeting to a room. We use a min heap to track the
earliest ending meeting. Whenever an old meeting ends before a new meeting starts, we remove the old meeting. If a person can attend all meetings, there must not be any overlaps between any meetings. After sorting the
Otherwise, we need an extra room. intervals, we can compare the current end and next start.

public int minMeetingRooms(Interval[] intervals) { public boolean canAttendMeetings(Interval[] intervals) {


if(intervals==null||intervals.length==0){ Arrays.sort(intervals, new Comparator<Interval>(){
return 0; public int compare(Interval a, Interval b){
} return a.start-b.start;
}
Comparator<Interval> comp = Comparator.comparing((Interval i)->i.start); });
Arrays.sort(intervals, comp);
for(int i=0; i<intervals.length-1; i++){
PriorityQueue<Integer> queue = new PriorityQueue<>(); if(intervals[i].end>intervals[i+1].start){
queue.offer(intervals[0].end); return false;
int count = 1; }
for(int i=1; i<intervals.length; i++){ }
int head = queue.peek();
if(intervals[i].start>=head){ return true;
queue.poll(); }
}else{
count++;
}
queue.offer(intervals[i].end);
}

return count;
}

There was a discussion in the comment about why a regular queue is not good enough. I draw an example
below to show why sorting based on start time and using a priority queue is necessary.

139 | 568 Program Creek 140 | 568 141 | 568


77 Range Addition

return result;
}

Time complexity is O(nlog(n)).


77 Range Addition 78 Merge K Sorted Arrays in Java
77.2 Java Solution 2
Assume you have an array of length n initialized with all 0’s and are given k update operations. This is a classic interview question. Another similar problem is "merge k sorted lists".
We can track each range’s start and end when iterating over the ranges. And in the final result array, adjust the
Each operation is represented as a triplet: [startIndex, endIndex, inc] which increments each element of subar- This problem can be solved by using a heap. The time complexity is O(nlog(k)), where n is the total number of
values on the change points. The following shows an example:
ray A[startIndex ... endIndex] (startIndex and endIndex inclusive) with inc. elements and k is the number of arrays.
Return the modified array after all k operations were executed. It takes O(log(k)) to insert an element to the heap and it takes O(log(k)) to delete the minimum element.
For example, Input: length = 5, updates = [[1,3,2],[2,4,3],[0,2,-2]] Output: [-2,0,3,5,3]
class ArrayContainer implements Comparable<ArrayContainer> {
int[] arr;
77.1 Java Solution 1 - heap int index;

public ArrayContainer(int[] arr, int index) {


public int[] getModifiedArray(int length, int[][] updates) { this.arr = arr;
int result[] = new int[length]; this.index = index;
if(updates==null || updates.length==0) }
return result;
@Override
//sort updates by starting index public int compareTo(ArrayContainer o) {
Arrays.sort(updates, new Comparator<int[]>(){ return this.arr[this.index] - o.arr[o.index];
public int compare(int[] a, int [] b){ }
return a[0]-b[0]; }
}
});
public class KSortedArray {
ArrayList<int[]> list = new ArrayList<int[]>(); public int[] getModifiedArray(int length, int[][] updates) { public static int[] mergeKSortedArray(int[][] arr) {
int[] result = new int[length]; //PriorityQueue is heap in Java
//create a heap sorted by ending index if(updates==null||updates.length==0) PriorityQueue<ArrayContainer> queue = new PriorityQueue<ArrayContainer>();
PriorityQueue<Integer> queue = new PriorityQueue<Integer>(new Comparator<Integer>(){ return result; int total=0;
public int compare(Integer a, Integer b){
return updates[a][1]-updates[b][1]; for(int i=0; i<updates.length; i++){ //add arrays to heap
} result[updates[i][0]] += updates[i][2]; for (int i = 0; i < arr.length; i++) {
}); if(updates[i][1]<length-1){ queue.add(new ArrayContainer(arr[i], 0));
result[updates[i][1]+1] -=updates[i][2]; total = total + arr[i].length;
int sum=0; } }
int j=0; }
for(int i=0; i<length; i++){ int m=0;
//substract value from sum when ending index is reached int v=0; int result[] = new int[total];
while(!queue.isEmpty() && updates[queue.peek()][1] < i){ for(int i=0; i<length; i++){
int top = queue.poll(); v += result[i]; //while heap is not empty
sum -= updates[top][2]; result[i]=v; while(!queue.isEmpty()){
} } ArrayContainer ac = queue.poll();
result[m++]=ac.arr[ac.index];
//add value to sum when starting index is reached return result;
while(j<updates.length && updates[j][0] <= i){ } if(ac.index < ac.arr.length-1){
sum = sum+updates[j][2]; queue.add(new ArrayContainer(ac.arr, ac.index+1));
queue.offer(j); Time complexity is O(n). }
j++; }
}
return result;
result[i]=sum; }
}
public static void main(String[] args) {

142 | 568 Program Creek 143 | 568 144 | 568


78 Merge K Sorted Arrays in Java

int[] arr1 = { 1, 3, 5, 7 };
int[] arr2 = { 2, 4, 6, 8 };
int[] arr3 = { 0, 9, 10, 11 };

int[] result = mergeKSortedArray(new int[][] { arr1, arr2, arr3 });


System.out.println(Arrays.toString(result)); 79 Merge k Sorted Lists 80 Rearrange String k Distance Apart
}
}
Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity. Given a non-empty string str and an integer k, rearrange the string such that the same characters are at least
distance k from each other.
All input strings are given in lowercase letters. If it is not possible to rearrange the string, return an empty
79.1 Analysis string "".
Example:
The simplest solution is using PriorityQueue. The elements of the priority queue are ordered according to their
natural ordering, or by a comparator provided at the construction time (in this case). str = "aabbcc", k = 3

Result: "abcabc"
79.2 Java Solution
The same letters are at least distance 3 from each other.

public ListNode mergeKLists(ListNode[] lists) {


if(lists==null||lists.length==0)
return null; 80.1 Java Solution
PriorityQueue<ListNode> queue = new PriorityQueue<ListNode>(new Comparator<ListNode>(){
public int compare(ListNode l1, ListNode l2){ public String rearrangeString(String str, int k) {
return l1.val - l2.val; if(k==0)
} return str;
});
//initialize the counter for each character
ListNode head = new ListNode(0); final HashMap<Character, Integer> map = new HashMap<Character, Integer>();
ListNode p = head; for(int i=0; i<str.length(); i++){
char c = str.charAt(i);
for(ListNode list: lists){ if(map.containsKey(c)){
if(list!=null) map.put(c, map.get(c)+1);
queue.offer(list); }else{
} map.put(c, 1);
}
while(!queue.isEmpty()){ }
ListNode n = queue.poll();
p.next = n; //sort the chars by frequency
p=p.next; PriorityQueue<Character> queue = new PriorityQueue<Character>(new Comparator<Character>(){
public int compare(Character c1, Character c2){
if(n.next!=null) if(map.get(c2).intValue()!=map.get(c1).intValue()){
queue.offer(n.next); return map.get(c2)-map.get(c1);
} }else{
return c1.compareTo(c2);
return head.next; }
}
} });

Time: log(k) * n. k is number of list and n is number of total elements.


In addition, from Java 8 comparator definition can be simplified as the following: for(char c: map.keySet())
queue.offer(c);
Comparator<ListNode> comp = Comparator.comparing(ListNode->ListNode.val);
PriorityQueue<ListNode> queue = new PriorityQueue<>(comp); StringBuilder sb = new StringBuilder();

int len = str.length();

Program Creek 145 | 568 146 | 568 147 | 568


80 Rearrange String k Distance Apart 81 Minimum Cost to Hire K Workers

}
while(!queue.isEmpty()){
class Worker{
int cnt = Math.min(k, len); int quality;
ArrayList<Character> temp = new ArrayList<Character>(); int wage;
81 Minimum Cost to Hire K Workers double ratio;
for(int i=0; i<cnt; i++){
if(queue.isEmpty()) public Worker(int q, int w){
return ""; There are N workers. The i-th worker has a quality[i] and a minimum wage expectation wage[i]. this.quality = q;
Now we want to hire exactly K workers to form a paid group. When hiring a group of K workers, we must this.wage = w;
char c = queue.poll(); pay them according to the following rules: Every worker in the paid group should be paid in the ratio of their this.ratio = (double)w/q;
sb.append(String.valueOf(c)); quality compared to other workers in the paid group. Every worker in the paid group must be paid at least their }
minimum wage expectation. Return the least amount of money needed to form a paid group satisfying the above }
map.put(c, map.get(c)-1); conditions.
Example:
if(map.get(c)>0){
temp.add(c); Input: quality = [10,20,5], wage = [70,50,30], K = 2
} Output: 105.00000
Explanation: We pay 70 to 0-th worker and 35 to 2-th worker.
len--;
}

for(char c: temp) 81.1 Java Solution


queue.offer(c);
} First, sort workers by their wage/quality ratio in ascending order. The smaller ratio value means better quality
and low wage. Then try the best ratio first and use the heap to track the largest quality. Given a ratio, the largest
return sb.toString();
quality is removed from the queue because it takes more wage.
}
class Solution {
public double mincostToHireWorkers(int[] quality, int[] wage, int K) {
ArrayList<Worker> list = new ArrayList<>();
for(int i=0; i<wage.length; i++){
list.add(new Worker(quality[i], wage[i]));
}
Comparator<Worker> comp = Comparator.comparing((Worker w) -> w.ratio);
Collections.sort(list, comp);

PriorityQueue<Integer> q = new PriorityQueue<>();


int sum = 0;
double result = Integer.MAX_VALUE;

for(int i=0; i<list.size(); i++){


Worker w = list.get(i);
sum += w.quality;
q.offer(-w.quality);

if(q.size()>K){
int extra = q.poll();
sum += extra;
}

if(q.size() == K){
result = Math.min(result, sum * w.ratio);
}
}

return result;
}

Program Creek 148 | 568 149 | 568 Program Creek 150 | 568
82 Contains Duplicate 83 Contains Duplicate II 84 Contains Duplicate III
Given an array of integers, find if the array contains any duplicates. Your function should return true if any value Given an array of integers and an integer k, return true if and only if there are two distinct indices i and j in the Given an array of integers, find out whether there are two distinct indices i and j in the array such that the
appears at least twice in the array, and it should return false if every element is distinct. array such that nums[i] = nums[j] and the difference between i and j is at most k. difference between nums[i] and nums[j] is at most t and the difference between i and j is at most k.

82.1 Java Solution 83.1 Java Solution 1 - HashMap 84.1 Java Solution 1 - Simple
This solution simple. Its time complexity is O(nlog(k)).
public boolean containsDuplicate(int[] nums) { public boolean containsNearbyDuplicate(int[] nums, int k) {
if(nums==null || nums.length==0) HashMap<Integer, Integer> map = new HashMap<Integer, Integer>(); public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) {
return false; if(nums==null||nums.length<2||k<0||t<0)
for(int i=0; i<nums.length; i++){ return false;
HashSet<Integer> set = new HashSet<Integer>(); if(map.containsKey(nums[i])){
for(int i: nums){ int pre = map.get(nums[i]); TreeSet<Long> set = new TreeSet<Long>();
if(!set.add(i)){ if(i-pre<=k) for(int i=0; i<nums.length; i++){
return true; return true; long curr = (long) nums[i];
} }
} long leftBoundary = (long) curr-t;
map.put(nums[i], i); long rightBoundary = (long) curr+t+1; //right boundary is exclusive, so +1
return false; } SortedSet<Long> sub = set.subSet(leftBoundary, rightBoundary);
} if(sub.size()>0)
return false; return true;
}
set.add(curr);

if(i>=k){ // or if(set.size()>=k+1)
83.2 Java Solution 2 - HashSet set.remove((long)nums[i-k]);
}
}
public boolean containsNearbyDuplicate(int[] nums, int k) {
if(nums==null || nums.length<2 || k==0) return false;
return false; }

int i=0;

HashSet<Integer> set = new HashSet<Integer>(); 84.2 Java Solution 2 - Deprecated


for(int j=0; j<nums.length; j++){
if(!set.add(nums[j])){
return true;
}

if(set.size()>=k+1){
set.remove(nums[i++]);
}
}

return false;
}
public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) {
if (k < 1 || t < 0)

151 | 568 152 | 568 153 | 568


84 Contains Duplicate III 85 Max Sum of Rectangle No Larger Than K

return false; int sum=0;


TreeSet<Integer> set = new TreeSet<Integer>();
TreeSet<Integer> set = new TreeSet<Integer>(); int result=Integer.MIN_VALUE;
set.add(0);
for (int i = 0; i < nums.length; i++) {
int c = nums[i]; 85 Max Sum of Rectangle No Larger Than K for(int i=0; i<arr.length; i++){
if ((set.floor(c) != null && c <= set.floor(c) + t) sum=sum+arr[i];
|| (set.ceiling(c) != null && c >= set.ceiling(c) -t))
return true; Given a non-empty 2D matrix matrix and an integer k, find the max sum of a rectangle in the matrix such that its Integer ceiling = set.ceiling(sum-k);
sum is no larger than k. if(ceiling!=null){
set.add(c); Example: result = Math.max(result, sum-ceiling);
}
if (i >= k) Given matrix = [
set.remove(nums[i - k]); [1, 0, 1], set.add(sum);
} [0, -2, 3] }
]
return false; k = 2 return result;
} }
The answer is 2. Because the sum of rectangle [[0, 1], [-2, 3]] is 2 and 2 is the max number no larger than k (k =
2). The time complexity is O(n*n*m*log(m)). If m is greater than n, this solution is fine. However, if m is less than
Note: The rectangle inside the matrix must have an area >0. What if the number of rows is much larger than n, then this solution is not optimal. In this case, we should reverse the row and column, like Solution 2.
the number of columns?

85.3 Java Solution 2


85.1 Analysis
We can solve this problem by comparing each submatrix. This method is trivial and we need a better solution. public int maxSumSubmatrix(int[][] matrix, int k) {
The key to the optimal solution is using a tree set to calculate the maximum sum of subarray close to k. if(matrix==null||matrix.length==0||matrix[0].length==0)
return 0;

int row=matrix.length;
85.2 Java Solution 1
int col=matrix[0].length;

public int maxSumSubmatrix(int[][] matrix, int k) { int m = Math.max(row, col);


if(matrix==null||matrix.length==0||matrix[0].length==0) int n = Math.min(row, col);
return 0; boolean isRowLarger = false;
if(row>col)
int m=matrix.length; isRowLarger=true;
int n=matrix[0].length;
int result = Integer.MIN_VALUE;
int result = Integer.MIN_VALUE;
for(int c1=0; c1<n; c1++){
for(int c1=0; c1<n; c1++){
int[] each = new int[m]; int[] each = new int[m];
for(int c2=c1; c2>=0; c2--){ for(int c2=c1; c2>=0; c2--){

for(int r=0; r<m; r++){ for(int r=0; r<m; r++){


each[r]+=matrix[r][c2]; each[r]+=isRowLarger?matrix[r][c2]:matrix[c2][r];
} }

result = Math.max(result, getLargestSumCloseToK(each, k)); result = Math.max(result, getLargestSumCloseToK(each, k));


} }
} }

return result; return result;


} }

public int getLargestSumCloseToK(int[] arr, int k){ public int getLargestSumCloseToK(int[] arr, int k){

Program Creek 154 | 568 155 | 568 Program Creek 156 | 568
85 Max Sum of Rectangle No Larger Than K 86 Maximum Sum of Subarray Close to K

int sum=0; set.add(0);


TreeSet<Integer> set = new TreeSet<Integer>();
int result=Integer.MIN_VALUE; for(int i=0; i<arr.length; i++){
set.add(0); sum=sum+arr[i];

for(int i=0; i<arr.length; i++){ 86 Maximum Sum of Subarray Close to K Integer ceiling = set.ceiling(sum-k);
sum=sum+arr[i]; if(ceiling!=null){
result = Math.max(result, sum-ceiling);
Integer ceiling = set.ceiling(sum-k); Given an array, find the maximum sum of subarray close to k but not larger than k. }
if(ceiling!=null){
result = Math.max(result, sum-ceiling); set.add(sum);
} 86.1 Java Solution }

set.add(sum); The solution to this problem is obvious when we draw the following diagram. return result;
} }

return result;
}

public int getLargestSumCloseToK(int[] arr, int k){


int sum=0;
TreeSet<Integer> set = new TreeSet<Integer>();
int result=Integer.MIN_VALUE;

Program Creek 157 | 568 158 | 568 Program Creek 159 | 568
87 Sliding Window Maximum

if(!deque.isEmpty()&&deque.peekFirst()==i-k)
deque.poll();

while(!deque.isEmpty()&&nums[deque.peekLast()]<nums[i]){
deque.removeLast();
87 Sliding Window Maximum } 88 Moving Average from Data Stream
deque.offer(i);
Given an array nums, there is a sliding window of size k which is moving from the very left of the array to the Given a stream of integers and a window size, calculate the moving average of all integers in the sliding window.
very right. You can only see the k numbers in the window. Each time the sliding window moves right by one if(i+1>=k)
position. result[i+1-k]=nums[deque.peek()];
} 88.1 Java Solution

87.1 Java Solution return result; This problem is solved by using a queue.
}
class MovingAverage {
double sum;
int size;
LinkedList<Integer> list;

/** Initialize your data structure here. */


public MovingAverage(int size) {
this.list = new LinkedList<>();
this.size = size;
}

public double next(int val) {


sum += val;
list.offer(val);

if(list.size()<=size){
return sum/list.size();
}

sum -= list.poll();

return sum/size;
}
}

public int[] maxSlidingWindow(int[] nums, int k) {


if(nums==null||nums.length==0)
return new int[0];

int[] result = new int[nums.length-k+1];

LinkedList<Integer> deque = new LinkedList<Integer>();


for(int i=0; i<nums.length; i++){

160 | 568 Program Creek 161 | 568 162 | 568


89 Find Median from Data Stream

89 Find Median from Data Stream 90 Data Stream as Disjoint Intervals


Median is the middle value in an ordered integer list. If the size of the list is even, there is no middle value. So Given a data stream input of non-negative integers a1, a2, ..., an, ..., summarize the numbers seen so far as a list
the median is the mean of the two middle value. of disjoint intervals.
For example, suppose the integers from the data stream are 1, 3, 7, 2, 6, ..., then the summary will be:
[1, 1] [1, 1], [3, 3] [1, 1], [3, 3], [7, 7] [1, 3], [7, 7] [1, 3], [6, 7] Follow up: What if there are lots of merges and the
89.1 Analysis number of disjoint intervals are small compared to the data stream’s size?

First of all, it seems that the best time complexity we can get for this problem is O(log(n)) of add() and O(1) of
getMedian(). This data structure seems highly likely to be a tree. 90.1 Analysis
We can use heap to solve this problem. In Java, the PriorityQueue class is a priority heap. We can use two
heaps to store the lower half and the higher half of the data stream. The size of the two heaps differs at most 1. We can store the interval in an array and each time iterator over the array and merge the new value to an existing
interval. This takes time O(n). If there are a lot of merges, we want to do it in log(n).
We can solve this problem using a tree set. The floor() method returns the greatest element in this set less than
or equal to the given element, or null if there is no such element. The higher() method returns the least element in
this set strictly greater than the given element, or null if there is no such element. Note: we use higher() instead
of ceiling() to exclude the given element.

90.2 Java Solution

public class SummaryRanges {


class MedianFinder {
PriorityQueue<Integer> minHeap = null; TreeSet<Interval> set;
PriorityQueue<Integer> maxHeap = null;
/** Initialize your data structure here. */
/** initialize your data structure here. */ public SummaryRanges() {
public MedianFinder() { set = new TreeSet<Interval>(new Comparator<Interval>(){
minHeap = new PriorityQueue<>(); public int compare(Interval a, Interval b){
maxHeap = new PriorityQueue<>(Comparator.reverseOrder()); return a.start-b.start;
} }
});
public void addNum(int num) { }
minHeap.offer(num);
maxHeap.offer(minHeap.poll()); public void addNum(int val) {
Interval t = new Interval(val, val);
if(minHeap.size()<maxHeap.size()){
minHeap.offer(maxHeap.poll()); Interval floor = set.floor(t);
} if(floor!=null){
} if(val<=floor.end){
return;
public double findMedian() { }else if(val == floor.end+1){
if(minHeap.size() > maxHeap.size()){ t.start = floor.start;
return minHeap.peek(); set.remove(floor);
}else { }
return (minHeap.peek()+maxHeap.peek())/2.0; }
}
} Interval ceil = set.higher(t);
} if(ceil!=null){
if(ceil.start==val+1){
t.end = ceil.end;

163 | 568 Program Creek 164 | 568 165 | 568


90 Data Stream as Disjoint Intervals

set.remove(ceil);
}
}

set.add(t);
} 91 Linked List Random Node 92 Shuffle an Array

public List<Interval> getIntervals() { Given a singly linked list, return a random node’s value from the linked list. Each node must have the same Shuffle a set of numbers without duplicates.
return new ArrayList(set); probability of being chosen.
//Arrays.asList(set.toArray(new Interval[0])); Follow up: What if the linked list is extremely large and its length is unknown to you? Could you solve this
} efficiently without using extra space? 92.1 Java Solution
}
How we make sure each the probability of each element get shuffled is very similar to the streaming random
91.1 Java Solution problem.
The algorithm is straightforward to understand, but the question is why it works. To have a working shuffle
This problem is trivial, so I focus on the follow-up problem. algorithm, every element in the array results in each position should be equal.
We want the probability of being chosen is 1/count.
Given a list 1 ->2 ->3 ->4 ->5 ->... ->n, the only time we can possibly select the third node is when the pointer
points to 3. The probability of selecting the third node is 1/3 * 3/4 * 4/5 * ... * (n-1)/n = 1/n.

public class Solution {

/** @param head The linked list’s head. Note that the head is guanranteed to be not null, so it
contains at least one node. */
Random r=null;
ListNode h=null;
public Solution(ListNode head) {
r = new Random();
h = head;
}

/** Returns a random node’s value. */


public int getRandom() {
int count=1;
ListNode p = h;
int result = 0;
while(p!=null){
if(r.nextInt(count)==0)
result= p.val;
count++;
p = p.next;
}
return result;
}
}

class Solution {
int[] original = null;
int[] shuffle = null;
Random rand = null;

public Solution(int[] nums) {


original = nums;
shuffle = Arrays.copyOf(nums, nums.length);

Program Creek 166 | 568 167 | 568 168 | 568


92 Shuffle an Array 93 Sort List

rand = new Random(); while(p1!=null && p2!=null){


} if(p2.next==null||p2.next.next==null){
return p1;
/** Resets the array to its original configuration and return it. */ }
public int[] reset() {
shuffle = Arrays.copyOf(original, original.length); 93 Sort List p1 = p1.next;
return shuffle; p2 = p2.next.next;
} }
LeetCode - Sort List:
/** Returns a random shuffling of the array. */ Sort a linked list in O(n log n) time using constant space complexity. return head;
public int[] shuffle() { }
for(int i=0; i<shuffle.length; i++){
int x = rand.nextInt(shuffle.length-i); 93.1 Analysis //merge two list
int idx = x+i; private ListNode merge(ListNode n1, ListNode n2){
If this problem does not have the constant space limitation, we can easily sort using a sorting method from Java ListNode head = new ListNode(0);
int tmp = shuffle[idx]; SDK. With the constant space limitation, we need to do some pointer manipulation. ListNode p = head;
shuffle[idx] = shuffle[i]; ListNode p1 = n1;
shuffle[i] = tmp;
• Break the list to two in the middle ListNode p2 = n2;
} • Recursively sort the two sub lists while(p1!=null && p2!=null){
if(p1.val<p2.val){
• Merge the two sub lists
return shuffle; p.next = p1;
} p1 = p1.next;
} }else{
93.2 Java Solution
p.next = p2;
p2 = p2.next;
When I revisit this problem in 2018, I wrote it the following way which is more concise.
}
/**
p = p.next;
* Definition for singly-linked list.
}
* public class ListNode {
* int val;
ListNode next; if(p1!=null){
*
ListNode(int x) { val = x; } p.next = p1;
*
}
* }
*/
class Solution { if(p2!=null){
public ListNode sortList(ListNode head) { p.next = p2;
if(head==null || head.next==null){ }
return head;
} return head.next;
}
//partition the list }
ListNode p1 = head;
ListNode firstEnd = getFirstEnd(head);
ListNode p2 = firstEnd.next;
firstEnd.next = null;

//sort each list


p1 = sortList(p1);
p2 = sortList(p2);

//merge two lists


return merge(p1, p2);
}

//get the list partition point


private ListNode getFirstEnd(ListNode head){
ListNode p1 = head;
ListNode p2 = head;

Program Creek 169 | 568 170 | 568 Program Creek 171 | 568
94 Quicksort Array in Java 94 Quicksort Array in Java

arr[start] = pivot; return;


arr[end] = temp;
// pick the pivot
return start; int middle = low + (high - low) / 2;
} int pivot = arr[middle];
94 Quicksort Array in Java }
// make left < pivot and right > pivot
You can use the example below to go through the code. int i = low, j = high;
Quicksort is a divide and conquer algorithm. It first divides a large list into two smaller sub-lists and then while (i <= j) {
recursively sort the two sub-lists. If we want to sort an array without any extra space, quicksort is a good option. while (arr[i] < pivot) {
On average, time complexity is O(n log(n)). i++;
The basic step of sorting an array are as follows: }

• Select a pivot while (arr[j] > pivot) {


• Move smaller elements to the left and move bigger elements to the right of the pivot j--;
}
• Recursively sort left part and right part

This post shows two versions of the Java implementation. The first one picks the rightmost element as the pivot if (i <= j) {
int temp = arr[i];
and the second one picks the middle element as the pivot.
arr[i] = arr[j];
arr[j] = temp;
i++;
94.1 Version 1: Rightmost element as pivot
j--;
}
The following is the Java Implementation using rightmost element as the pivot.
}
public class QuickSort {
// recursively sort two sub parts
public static void main(String[] args) { if (low < j)
int[] arr = {4, 5, 1, 2, 3, 3}; quickSort(arr, low, j);
quickSort(arr, 0, arr.length-1);
System.out.println(Arrays.toString(arr)); if (high > i)
} quickSort(arr, i, high);
}
public static void quickSort(int[] arr, int start, int end){ }

int partition = partition(arr, start, end); Output:


9 2 4 7 3 7 10 2 3 4 7 7 9 10
if(partition-1>start) { Here is a very good animation of quicksort.
quickSort(arr, start, partition - 1); 94.2 Version 2: Middle element as pivot
}
if(partition+1<end) {
quickSort(arr, partition + 1, end); public class QuickSort {
} public static void main(String[] args) {
} int[] x = { 9, 2, 4, 7, 3, 7, 10 };
System.out.println(Arrays.toString(x));
public static int partition(int[] arr, int start, int end){
int pivot = arr[end]; int low = 0;
int high = x.length - 1;
for(int i=start; i<end; i++){
if(arr[i]<pivot){ quickSort(x, low, high);
int temp= arr[start]; System.out.println(Arrays.toString(x));
arr[start]=arr[i]; }
arr[i]=temp;
start++; public static void quickSort(int[] arr, int low, int high) {
} if (arr == null || arr.length == 0)
} return;

int temp = arr[start]; if (low >= high)

172 | 568 Program Creek 173 | 568 Program Creek 174 | 568
95 Kth Largest Element in an Array

return getKth(nums.length - k +1, nums, 0, nums.length - 1);


}

public int getKth(int k, int[] nums, int start, int end) {

95 Kth Largest Element in an Array int pivot = nums[end]; 96 Sort Colors


int left = start;
Find the kth largest element in an unsorted array. Note that it is the kth largest element in the sorted order, not int right = end; Given an array with n objects colored red, white or blue, sort them so that objects of the same color are adjacent,
the kth distinct element. with the colors in the order red, white and blue.
For example, given [3,2,1,5,6,4] and k = 2, return 5. while (true) { Here, we will use the integers 0, 1, and 2 to represent the color red, white, and blue respectively.
Note: You may assume k is always valid, 1 ≤ k ≤ array’s length.
while (nums[left] < pivot && left < right) {
left++; 96.1 Java Solution - Counting Sort
95.1 Java Solution 1 - Sorting }
We can get the count of each element and project them to the original array.
while (nums[right] >= pivot && right > left) {
public int findKthLargest(int[] nums, int k) { right--; public void sortColors(int[] nums) {
Arrays.sort(nums); } if(nums==null||nums.length<2){
return nums[nums.length-k]; return;
} if (left == right) { }
break;
Time is O(nlog(n)). The problem of this solution is that sorting all elements is not necessary and is a overkill } int[] countArray = new int[3];
for getting just one element. for(int i=0; i<nums.length; i++){
swap(nums, left, right); countArray[nums[i]]++;
} }
95.2 Java Solution 2 - Heap
swap(nums, left, end); int j = 0;
We can use a min heap to solve this problem. The heap stores the top k largest elements.The top of the heap is int k = 0;
if (k == left + 1) { while(j<=2){
the Kth Largest element and all other elements are greater than the heap top. Whenever the size is greater than
return pivot; if(countArray[j]!=0){
k, delete the min. Time complexity is O(nlog(k)). Space complexity is O(k) for storing the top k numbers.
} else if (k < left + 1) { nums[k++]=j;
public int findKthLargest(int[] nums, int k) { return getKth(k, nums, start, left - 1); countArray[j] = countArray[j]-1;
PriorityQueue<Integer> q = new PriorityQueue<Integer>(k); } else { }else{
for(int i: nums){ return getKth(k, nums, left + 1, end); j++;
q.offer(i); } }
} }
if(q.size()>k){ }
q.poll(); public void swap(int[] nums, int n1, int n2) {
} int tmp = nums[n1];
} nums[n1] = nums[n2];
nums[n2] = tmp;
return q.peek(); }
}
Average case time is O(n), worst case time is O(n2̂).
Time complexity of n*log(k) is an improvement to Solution 1. However, this solution requires O(k) space
complexity and it is also maintained k-element heap.

95.3 Java Solution 3 - Quick Sort


This problem can also be solved by using a similar method like quicksort.

public int findKthLargest(int[] nums, int k) {


if (k < 1 || nums == null) {
return 0;
}

175 | 568 Program Creek 176 | 568 177 | 568


97 Maximum Gap

int low;
int high;
public Bucket(){
low = -1;
high = -1;
97 Maximum Gap } 98 Group Anagrams
}

Given an unsorted array, find the maximum difference between the successive elements in its sorted form. public int maximumGap(int[] num) { Given an array of strings, return all groups of strings that are anagrams.
Try to solve it in linear time/space. Return 0 if the array contains less than 2 elements. You may assume all if(num == null || num.length < 2){ An anagram is a type of word play, the result of rearranging the letters of a word or phrase to produce a new word or
elements in the array are non-negative integers and fit in the 32-bit signed integer range. return 0; phrase, using all the original letters exactly once; for example, Torchwood can be rearranged into Doctor Who.
}

97.1 Analysis int max = num[0]; 98.1 Java Solution


int min = num[0];
We can use a bucket-sort like algorithm to solve this problem in time of O(n) and space O(n). The basic idea for(int i=1; i<num.length; i++){ If two strings are anagram to each other, their sorted sequence is the same.
is to project each element of the array to an array of buckets. Each bucket tracks the maximum and minimum max = Math.max(max, num[i]);
min = Math.min(min, num[i]); public List<List<String>> groupAnagrams(String[] strs) {
elements. Finally, scanning the bucket list, we can get the maximum gap.
} List<List<String>> result = new ArrayList<List<String>>();
The key part is to get the interval:

From: interval * (num[i] - min) = 0 and interval * (max -num[i]) = n // initialize an array of buckets HashMap<String, ArrayList<String>> map = new HashMap<String, ArrayList<String>>();
interval = num.length / (max - min) Bucket[] buckets = new Bucket[num.length+1]; //project to (0 - n) for(String str: strs){
for(int i=0; i<buckets.length; i++){ char[] arr = new char[26];
buckets[i] = new Bucket(); for(int i=0; i<str.length(); i++){
The following diagram shows an example.
} arr[str.charAt(i)-’a’]++;
}
double interval = (double) num.length / (max - min); String ns = new String(arr);
//distribute every number to a bucket array
for(int i=0; i<num.length; i++){ if(map.containsKey(ns)){
int index = (int) ((num[i] - min) * interval); map.get(ns).add(str);
}else{
if(buckets[index].low == -1){ ArrayList<String> al = new ArrayList<String>();
buckets[index].low = num[i]; al.add(str);
buckets[index].high = num[i]; map.put(ns, al);
}else{ }
buckets[index].low = Math.min(buckets[index].low, num[i]); }
buckets[index].high = Math.max(buckets[index].high, num[i]);
} result.addAll(map.values());
}
return result;
//scan buckets to find maximum gap }
int result = 0;
int prev = buckets[0].high;
for(int i=1; i<buckets.length; i++){
if(buckets[i].low != -1){ 98.2 Time Complexity
result = Math.max(result, buckets[i].low-prev);
prev = buckets[i].high; If the average length of verbs is m and array length is n, then the time is O(n*m).
}

return result;
}

97.2 Java Solution

class Bucket{

178 | 568 Program Creek 179 | 568 180 | 568


99 Ugly Number 100 Ugly Number II 101 Super Ugly Number
Write a program to check whether a given number is an ugly number. Ugly numbers are positive numbers whose Write a program to find the n-th ugly number. Ugly numbers are positive numbers whose prime factors only Write a program to find the nth super ugly number.
prime factors only include 2, 3, 5. For example, 6, 8 are ugly while 14 is not ugly since it includes another prime 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. Note that 1 is Super ugly numbers are positive numbers whose all prime factors are in the given prime list primes of size k.
factor 7. Note that 1 is typically treated as an ugly number. typically treated as an ugly number. For example, [1, 2, 4, 7, 8, 13, 14, 16, 19, 26, 28, 32] is the sequence of the first 12 super ugly numbers given primes
= [2, 7, 13, 19] of size 4.
Note: (1) 1 is a super ugly number for any given primes. (2) The given numbers in primes are in ascending
99.1 Java Solution 100.1 Java Solution order. (3) 0 <k <= 100, 0 <n <= 106, 0 <primes[i] <1000.

public boolean isUgly(int num) { public int nthUglyNumber(int n) {


if(num==0) return false; if(n<=0)
101.1 Java Solution
if(num==1) return true; return 0;
Keep adding minimum values to results and updating the time value for the chosen prime number in each loop.
if(num%2==0){ ArrayList<Integer> list = new ArrayList<Integer>();
public int nthSuperUglyNumber(int n, int[] primes) {
num=num/2; list.add(1);
int[] times = new int[primes.length];
return isUgly(num);
int[] result = new int[n];
} int i=0;
result[0] = 1; // first is 1
int j=0;
if(num%3==0){ int k=0;
for (int i = 1; i < n; i++) {
num=num/3;
int min = Integer.MAX_VALUE;
return isUgly(num); while(list.size()<n){
for (int j = 0; j < primes.length; j++) {
} int m2 = list.get(i)*2;
min = Math.min(min, primes[j] * result[times[j]]);
int m3 = list.get(j)*3;
}
if(num%5==0){ int m5 = list.get(k)*5;
num=num/5;
result[i] = min;
return isUgly(num); int min = Math.min(m2, Math.min(m3, m5));
} list.add(min);
for (int j = 0; j < times.length; j++) {
if (result[times[j]] * primes[j] == min) {
return false; if(min==m2)
times[j]++;
} i++;
}
}
if(min==m3)
}
j++;
return result[n - 1];
if(min==m5)
}
k++;
}

return list.get(list.size()-1);
}

181 | 568 182 | 568 183 | 568


103 Rotate Array in Java

However, the time is O(n*k).


Here is an example (length=7, order=3):

i=0
0 1 2 3 4 5 6
102 Find K Pairs with Smallest Sums 103 Rotate Array in Java 0 1 2 3 4 6 5
...
6 0 1 2 3 4 5
You are given two integer arrays nums1 and nums2 sorted in ascending order and an integer k. Rotate an array of n elements to the right by k steps. i=1
Define a pair (u,v) which consists of one element from the first array and one element from the second array. For example, with n = 7 and k = 3, the array [1,2,3,4,5,6,7] is rotated to [5,6,7,1,2,3,4]. How many different ways 6 0 1 2 3 5 4
Find the k pairs (u1,v1),(u2,v2) ...(uk,vk) with the smallest sums. do you know to solve this problem? ...
Example: 5 6 0 1 2 3 4
i=2
Given nums1 = [1,7,11], nums2 = [2,4,6], k = 3 103.1 Solution 1 - Intermediate Array 5 6 0 1 2 4 3
...
Return: [1,2],[1,4],[1,6] In a straightforward way, we can create a new array and then copy elements to the new array. Then change the 4 5 6 0 1 2 3
original array by using System.arraycopy().
The first 3 pairs are returned from the sequence:
[1,2],[1,4],[1,6],[7,2],[7,4],[11,2],[7,6],[11,4],[11,6] public void rotate(int[] nums, int k) {
if(k > nums.length) 103.3 Solution 3 - Reversal
k=k%nums.length;
Can we do this in O(1) space and in O(n) time? The following solution does.
102.1 Java Solution int[] result = new int[nums.length]; Assuming we are given 1,2,3,4,5,6 and order 2. The basic idea is:

This problem is similar to Super Ugly Number. The basic idea is using an array to track the index of the next for(int i=0; i < k; i++){ 1. Divide the array two parts: 1,2,3,4 and 5, 6
element in the other array. result[i] = nums[nums.length-k+i]; 2. Reverse first part: 4,3,2,1,5,6
The best way to understand this solution is using an example such as nums1=1,3,11 and nums2=2,4,8. } 3. Reverse second part: 4,3,2,1,6,5
4. Reverse the whole array: 5,6,1,2,3,4
public List<int[]> kSmallestPairs(int[] nums1, int[] nums2, int k) { int j=0;
int total=nums1.length*nums2.length; for(int i=k; i<nums.length; i++){
if(total<k){ result[i] = nums[j]; public static void rotate(int[] arr, int order) {
k=total; j++; if (arr == null || arr.length==0 || order < 0) {
} } throw new IllegalArgumentException("Illegal argument!");
}
List<int[]> result = new ArrayList<int[]>(); System.arraycopy( result, 0, nums, 0, nums.length );
int[] idx = new int[nums1.length];//track each element’s cursor in nums2 } if(order > arr.length){
while(k>0){ order = order %arr.length;
int min=Integer.MAX_VALUE; Space is O(n) and time is O(n). You can check out the difference between System.arraycopy() and Arrays.copyOf(). }
int minIdx=-1;
for(int i=0; i<nums1.length; i++){ //length of first part
if(idx[i]<nums2.length && nums1[i]+nums2[idx[i]]<min){ 103.2 Solution 2 - Bubble Rotate int a = arr.length - order;
minIdx=i;
min=nums1[i]+nums2[idx[i]]; Can we do this in O(1) space? reverse(arr, 0, a-1);
} reverse(arr, a, arr.length-1);
This solution is like a bubble sort.
} reverse(arr, 0, arr.length-1);
result.add(new int[]{nums1[minIdx],nums2[idx[minIdx]]}); public static void rotate(int[] arr, int order) {
idx[minIdx]++; if (arr == null || order < 0) { }
k--; throw new IllegalArgumentException("Illegal argument!");
} } public static void reverse(int[] arr, int left, int right){
if(arr == null || arr.length == 1)
return result; for (int i = 0; i < order; i++) { return;
} for (int j = arr.length - 1; j > 0; j--) {
int temp = arr[j]; while(left < right){
arr[j] = arr[j - 1]; int temp = arr[left];
arr[j - 1] = temp; arr[left] = arr[right];
} arr[right] = temp;
} left++;
} right--;

184 | 568 185 | 568 Program Creek 186 | 568


103 Rotate Array in Java

}
}

104 Reverse Words in a String II 105 Missing Number


Given an input string, reverse the string word by word. A word is defined as a sequence of non-space characters. Given an array containing n distinct numbers taken from 0, 1, 2, ..., n, find the one that is missing from the array.
The input string does not contain leading or trailing spaces and the words are always separated by a single For example, given nums = [0, 1, 3] return 2.
space.
For example, Given s = "the sky is blue", return "blue is sky the".
Could you do it in-place without allocating extra space?
105.1 Java Solution 1 - Math

public int missingNumber(int[] nums) {


104.1 Java Solution int sum=0;
for(int i=0; i<nums.length; i++){
sum+=nums[i];
public void reverseWords(char[] s) {
}
int i=0;
for(int j=0; j<s.length; j++){
int n=nums.length;
if(s[j]==’ ’){
return n*(n+1)/2-sum;
reverse(s, i, j-1);
}
i=j+1;
}
}

reverse(s, i, s.length-1);
105.2 Java Solution 2 - Bit

reverse(s, 0, s.length-1); public int missingNumber(int[] nums) {


}
int miss=0;
public void reverse(char[] s, int i, int j){ for(int i=0; i<nums.length; i++){
while(i<j){ miss ^= (i+1) ^nums[i];
char temp = s[i]; }
s[i]=s[j];
s[j]=temp; return miss;
i++; }
j--;
}
}
105.3 Java Solution 3 - Binary Search

public int missingNumber(int[] nums) {


Arrays.sort(nums);
int l=0, r=nums.length;
while(l<r){
int m = (l+r)/2;
if(nums[m]>m){
r=m;
}else{
l=m+1;
}
}

return r;
}

Program Creek 187 | 568 188 | 568 189 | 568


106 Find the Duplicate Number

public int findDuplicate(int[] nums) {


int sum = 0;
for(int i: nums){
sum+=i;
106 Find the Duplicate Number } 107 First Missing Positive
int n=nums.length;
Given an array containing n + 1 integers where each integer is between 1 and n (inclusive), prove that at least one return sum - ((n-1)*n)/2; Given an unsorted integer array, find the first missing positive integer. For example, given [1,2,0] return 3 and
duplicate number must exist. Assume that there is only one duplicate number, find the duplicate one. } [3,4,-1,1] return 2.
Note: 1) You must not modify the array (assume the array is read only). 2) You must use only constant, O(1) Your algorithm should run in O(n) time and uses constant space.
extra space. 3) Your runtime complexity should be less than O(n2̂). 4) There is only one duplicate number in the
array, but it could be repeated more than once.
107.1 Analysis

106.1 Java Solution - Finding Cycle This problem can solve by using a bucket-sort like algorithm. Let’s consider finding first missing positive and 0
first. The key fact is that the ith element should be i, so we have: i==A[i] A[i]==A[A[i]]
The following shows how fast and slow pointers solution works. It basically contains 2 steps: 1) find the meeting For example, given an array 1,2,0,4, the algorithm does the following:
point 2) start from the beginning and the meeting point respectively and find the intersection point.

public int findDuplicate(int[] nums) {


int firstMissingPositiveAnd0(int A[]) {
int slow = 0;
int n = A.length;
int fast = 0;
for (int i = 0; i < n; i++) {
// when the ith element is not i
do{
while (A[i] != i) {
slow = nums[slow];
// no need to swap when ith element is out of range [0,n]
fast = nums[nums[fast]];
if (A[i] < 0 || A[i] >= n)
} while(slow != fast);
break;
int find = 0;
//handle duplicate elements
if(A[i]==A[A[i]])
while(find != slow){
break;
slow = nums[slow];
// swap elements
find = nums[find];
int temp = A[i];
}
A[i] = A[temp];
return find;
A[temp] = temp;
}
}
}
If we can assume there is only one duplicate number, it can be easily solved by using the sum of the array.

190 | 568 Program Creek 191 | 568 192 | 568


107 First Missing Positive

for (int i = 0; i < n; i++) {


if (A[i] != i)
return i;
}
108 Queue Reconstruction by Height 109 Binary Watch
return n;
}
Suppose you have a random list of people standing in a queue. Each person is described by a pair of integers (h, Given a non-negative integer n which represents the number of LEDs that are currently on, return all possible
k), where h is the height of the person and k is the number of people in front of this person who have a height times the watch could represent.
greater than or equal to h. Write an algorithm to reconstruct the queue. Example:
107.2 Java Solution Note: The number of people is less than 1,100. Input: n = 1 Return: ["1:00", "2:00", "4:00", "8:00", "0:01", "0:02", "0:04", "0:08", "0:16", "0:32"]
Example
This problem only considers positive numbers, so we need to shift 1 offset. The ith element is i+1. Input: [[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]]
Output: [[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]] 109.1 Accepted Java Solution
public int firstMissingPositive(int[] A) {
int n = A.length;
public List<String> readBinaryWatch(int num) {
108.1 Analysis List<String> result = new ArrayList<String>();
for (int i = 0; i < n; i++) {
while (A[i] != i + 1) {
The key to solve this problem is finding the start point of reconstruction. For this problem, we can start adding
if (A[i] <= 0 || A[i] >= n) for(int i=0; i<12; i++){
the largest element first. The basic idea is to keep adding the largest element each time, until all elements are in for(int j=0; j<60; j++){
break;
place. int total = countDigits(i)+countDigits(j);
if(A[i]==A[A[i]-1]) if(total==num){
break; String s="";
108.2 Java Solution s+=i+":";
int temp = A[i];
A[i] = A[temp - 1]; if(j<10){
public int[][] reconstructQueue(int[][] people) {
A[temp - 1] = temp; s+="0"+j;
int[][] result = new int[people.length][];
} }else{
Arrays.sort(people, new Comparator<int[]>(){
} s+=j;
public int compare(int[] a1, int[] a2){
}
if(a1[0]!=a2[0]){
for (int i = 0; i < n; i++){
return a2[0]-a1[0];
if (A[i] != i + 1){ result.add(s);
}else{
return i + 1; }
return a1[1]-a2[1];
} }
}
} }
}
});
return n + 1; return result;
} }
ArrayList<int[]> list = new ArrayList<int[]>();

public int countDigits(int num){


for(int i=0; i<people.length; i++){
int result=0;
int[] arr = people[i];
list.add(arr[1],arr);
while(num>0){
}
if((num&1)==1){
result++;
for(int i=0; i<people.length; i++){
}
result[i]=list.get(i);
}
num>>=1;
}
return result;
}
return result;
}
Time complexity of this solution is O(n2̂).
Time complexity is constant (12*60).

Program Creek 193 | 568 194 | 568 195 | 568


109 Binary Watch 109 Binary Watch

109.2 Naive Solution continue;

if(sum<10 && !isHour){


public class Solution { result.add("0"+sum);
public List<String> readBinaryWatch(int num) { }else{
result.add(""+sum); 110 Search a 2D Matrix
List<String> result = new ArrayList<String>(); }
}
for(int i=0; i<=4; i++){ Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has properties:
int h=i; return result; 1) Integers in each row are sorted from left to right. 2) The first integer of each row is greater than the last
int m=num-i; } integer of the previous row.
For example, consider the following matrix:
ArrayList<ArrayList<Integer>> hSet = new ArrayList<ArrayList<Integer>>(); public void subSet(int k, int m, int start, ArrayList<Integer> temp, ArrayList<ArrayList<Integer>>
subSet(h, 4, 1, new ArrayList<Integer>(), hSet); result){ [
if(k==0){ [1, 3, 5, 7],
ArrayList<ArrayList<Integer>> mSet = new ArrayList<ArrayList<Integer>>(); result.add(new ArrayList<Integer>(temp)); [10, 11, 16, 20],
subSet(m, 6, 1, new ArrayList<Integer>(), mSet); return; [23, 30, 34, 50]
} ]
ArrayList<String> hoursList = new ArrayList<String>();
ArrayList<String> minsList = new ArrayList<String>(); for(int i=start; i<=m; i++){ Given target = 3, return true.
temp.add(i);
if(hSet.size()==0){ subSet(k-1, m, i+1, temp, result);
hoursList.add("0"); temp.remove(temp.size()-1); 110.1 Java Solution
}else{ }
hoursList.addAll(getTime(hSet, true)); } This is a typical problem of binary search.
} } You may try to solve this problem by finding the row first and then the column. There is no need to do that.
Because of the matrix’s special features, the matrix can be considered as a sorted array. The goal is to find the
element in this sorted array by using binary search.
if(mSet.size()==0){
minsList.add("00"); public class Solution {
}else{ public boolean searchMatrix(int[][] matrix, int target) {
minsList.addAll(getTime(mSet, false)); if(matrix==null || matrix.length==0 || matrix[0].length==0)
} return false;

for(int x=0; x<hoursList.size(); x++){ int m = matrix.length;


for(int y=0; y<minsList.size(); y++){ int n = matrix[0].length;
result.add(hoursList.get(x)+":"+minsList.get(y));
} int start = 0;
} int end = m*n-1;

} while(start<=end){
int mid=(start+end)/2;
int midX=mid/n;
return result; int midY=mid%n;
}
if(matrix[midX][midY]==target)
public ArrayList<String> getTime(ArrayList<ArrayList<Integer>> lists, boolean isHour){ return true;
ArrayList<String> result = new ArrayList<String>();
if(matrix[midX][midY]<target){
for(ArrayList<Integer> l : lists){ start=mid+1;
int sum=0; }else{
for(int i: l){ end=mid-1;
sum+= (1<<(i-1)); }
} }
if(isHour && sum>=12)
continue; return false;
}
if(!isHour&&sum>=60) }

Program Creek 196 | 568 Program Creek 197 | 568 198 | 568
111 Search a 2D Matrix II

for(int j=j1;j<=j2;j++){
if(target > matrix[i2][j]){
return helper(matrix, i1, i2, j+1, j2, target);
}else if(target == matrix[i2][j]){
111 Search a 2D Matrix II return true; 112 Kth Smallest Element in a Sorted Matrix
}
}
Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the following properties: Given a n x n matrix where each of the rows and columns are sorted in ascending order, find the kth smallest
Integers in each row are sorted in ascending from left to right. Integers in each column are sorted in ascending for(int i=i1;i<=i2;i++){ element in the matrix.
from top to bottom. if(target > matrix[i][j2]){ Note that it is the kth smallest element in the sorted order, not the kth distinct element.
For example, consider the following matrix: return helper(matrix, i1, i+1, j1, j2, target); Example:
}else if(target == matrix[i][j2]){
[ return true; matrix = [
[1, 4, 7, 11, 15], } [ 1, 5, 9],
[2, 5, 8, 12, 19], } [10, 11, 13],
[3, 6, 9, 16, 22], [12, 13, 15]
[10, 13, 14, 17, 24], return false; ],
[18, 21, 23, 26, 30] }
] k = 8,
return 13.
Given target = 5, return true.
111.2 Java Solution 2
112.1 Java Solution
111.1 Java Solution 1 Time Complexity: O(m + n)
This problem is similar to Search a 2D Matrix II. The start point of such a sorted matrix is left-bottom corner.
In a naive approach, we can use the matrix boundary to reduce the search space. Here is a simple recursive public boolean searchMatrix(int[][] matrix, int target) {
implementation. int m=matrix.length-1; public int kthSmallest(int[][] matrix, int k) {
int n=matrix[0].length-1; int m=matrix.length;
public boolean searchMatrix(int[][] matrix, int target) {
int i1=0; int i=m; int lower = matrix[0][0];
int i2=matrix.length-1; int j=0; int upper = matrix[m-1][m-1];
int j1=0;
int j2=matrix[0].length-1; while(i>=0 && j<=n){ while(lower<upper){
if(target < matrix[i][j]){ int mid = lower + ((upper-lower)>>1);
return helper(matrix, i1, i2, j1, j2, target); i--; int count = count(matrix, mid);
} }else if(target > matrix[i][j]){ if(count<k){
j++; lower=mid+1;
public boolean helper(int[][] matrix, int i1, int i2, int j1, int j2, int target){ }else{ }else{
return true; upper=mid;
if(i1>i2||j1>j2) } }
return false; } }

for(int j=j1;j<=j2;j++){ return false; return upper;


if(target < matrix[i1][j]){ } }
return helper(matrix, i1, i2, j1, j-1, target);
}else if(target == matrix[i1][j]){ private int count(int[][] matrix, int target){
return true; int m=matrix.length;
} int i=m-1;
} int j=0;
int count = 0;
for(int i=i1;i<=i2;i++){
if(target < matrix[i][j1]){ while(i>=0&&j<m){
return helper(matrix, i1, i-1, j1, j2, target); if(matrix[i][j]<=target){
}else if(target == matrix[i][j1]){ count += i+1;
return true; j++;
} }else{
} i--;

199 | 568 Program Creek 200 | 568 201 | 568


112 Kth Smallest Element in a Sorted Matrix 113 Design Snake Game

} case "R":
} y++;
break;
return count; case "D":
} x++;
113 Design Snake Game break;
}

Design a Snake game that is played on a device with screen size = width x height. Play the game online if you if(!isValid(x,y)){
are not familiar with the game. return -1;
The snake is initially positioned at the top left corner (0,0) with length = 1 unit. }
You are given a list of food’s positions in row-column order. When a snake eats the food, its length and the
game’s score both increase by 1. return process(x, y);
Each food appears one by one on the screen. For example, the second food will not appear until the first food }
was eaten by the snake.
When a food does appear on the screen, it is guaranteed that it will not appear on a block occupied by the public boolean isValid(int x, int y){
if(x<0 || x>=row || y<0 || y>=col)
snake.
return false;

return true;
113.1 Java Solution
}

We can use a queue to track the snake positions.


public int process(int x, int y){
public class SnakeGame {
int[][] food; if(index==food.length){
int index; queue.poll();
int row, col;
int x, y; }else if(food[index][0]==x && food[index][1]==y){
int len; len++;
LinkedList<int[]> queue; index++;
/** Initialize your data structure here. }else{
@param width - screen width queue.poll();
@param height - screen height }
@param food - A list of food positions
E.g food = [[1,1], [1,0]] means the first food is positioned at [1,1], the second is at [1,0]. */ for(int[] p: queue){
public SnakeGame(int width, int height, int[][] food) { if(p[0]==x&&p[1]==y)
this.food=food; return -1;
this.index=0; }
this.x=0;
this.y=0; queue.offer(new int[]{x,y});
this.row=height;
this.col=width; return len;
this.queue= new LinkedList<int[]>(); }
this.queue.offer(new int[]{0, 0}); }
}

/** Moves the snake.


@param direction - ’U’ = Up, ’L’ = Left, ’R’ = Right, ’D’ = Down
@return The game’s score after the move. Return -1 if game over.
Game over when snake crosses the screen boundary or bites its body. */
public int move(String direction) {
switch(direction){
case "U":
x--;
break;
case "L":
y--;
break;

Program Creek 202 | 568 203 | 568 Program Creek 204 | 568
114 Number of Islands II

return i;
}

114 Number of Islands II 115 Number of Connected Components in an


A 2d grid map of m rows and n columns is initially filled with water. We may perform an addLand operation
Undirected Graph
which turns the water at position (row, col) into a land. Given a list of positions to operate, count the number of
islands after each addLand operation. An island is surrounded by water and is formed by connecting adjacent Given n nodes labeled from 0 to n - 1 and a list of undirected edges (each edge is a pair of nodes), write a function
lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water. to find the number of connected components in an undirected graph.
For example:

114.1 Java Solution 0 3


| |
Use an array to track the parent node for each cell. 1 --- 2 4

public List<Integer> numIslands2(int m, int n, int[][] positions) { Given n = 5 and edges = [[0, 1], [1, 2], [3, 4]], return 2.
int[] rootArray = new int[m*n];
Arrays.fill(rootArray,-1);
115.1 Java Solution - Union-find
ArrayList<Integer> result = new ArrayList<Integer>();
This problem can be solved by using union-find beautifully. Initially, there are n nodes. The nodes that are
int[][] directions = {{-1,0},{0,1},{1,0},{0,-1}};
involved in each edge is merged.
int count=0;

for(int k=0; k<positions.length; k++){


count++;

int[] p = positions[k];
int index = p[0]*n+p[1];
rootArray[index]=index;//set root to be itself for each node

for(int r=0;r<4;r++){
int i=p[0]+directions[r][0];
int j=p[1]+directions[r][1];

if(i>=0&&j>=0&&i<m&&j<n&&rootArray[i*n+j]!=-1){
//get neighbor’s root
int thisRoot = getRoot(rootArray, i*n+j);
if(thisRoot!=index){
rootArray[thisRoot]=index;//set previous root’s root
count--;
}
}
}

result.add(count);
}

return result;
}

public int getRoot(int[] arr, int i){


while(i!=arr[i]){
i=arr[i];
}

205 | 568 Program Creek 206 | 568 207 | 568


115 Number of Connected Components in an Undirected Graph 115 Number of Connected Components in an Undirected Graph

return count;
}

public int getRoot(int[] arr, int i){ 116 Most Stones Removed with Same Row or
while(arr[i]!=i){
arr[i]= arr[arr[i]]; Column
i=arr[i];
}
return i; The easiest solution for this problem is the union-find. The number of island problem can help understand how
} union-find works.
The basic idea is that we use a disjoint set to track each component. Whenever two stones can be connected,
There are k loops and each loop processing the root array costs log(n). Therefore, time complexity is O(k*log(n)). the number of islands decrease one. The final result, the number of movement, is the total number of stones - the
number of islands.
Example 1:

Input: stones = [[0,0],[0,1],[1,0],[1,2],[2,1],[2,2]]


Output: 5

Note:

1 <= stones.length <= 1000


0 <= stones[i][j] < 10000

116.1 Java Solution 1 - Regular Disjoint Set

class Solution {
int[] root = new int[1000]; //value is index
int result = 0;

public int removeStones(int[][] stones) {


result = stones.length;
for(int i=0; i<stones.length; i++){
public int countComponents(int n, int[][] edges) { root[i]=i;
int count = n; }

int[] root = new int[n]; for(int i=0; i<stones.length; i++){


// initialize each node is an island for(int j=i+1; j<stones.length; j++){
for(int i=0; i<n; i++){ if(stones[i][0]==stones[j][0] || stones[i][1]==stones[j][1]){
root[i]=i; union(i, j);
} }
}
for(int i=0; i<edges.length; i++){ }
int x = edges[i][0];
int y = edges[i][1]; return stones.length-result;
}
int xRoot = getRoot(root, x);
int yRoot = getRoot(root, y); public void union(int i, int j){
int ri = getRoot(i);
if(xRoot!=yRoot){ int rj = getRoot(j);
count--;
root[xRoot]=yRoot; if(ri==rj){
} return;
}

Program Creek 208 | 568 Program Creek 209 | 568 210 | 568
116 Most Stones Removed with Same Row or Column 116 Most Stones Removed with Same Row or Column

Time complexity is log(20000)*N = O(N)


root[getRoot(i)]=getRoot(j);
result--;
}

public int getRoot(int i){ 117 Longest Increasing Path in a Matrix


while(i!=root[i]){
i=root[i];
} Given an integer matrix, find the length of the longest increasing path.
From each cell, you can either move to four directions: left, right, up or down. You may NOT move diagonally
return i; or move outside of the boundary
} Example 1:
}
Input: nums =
Time complexity is O(N2̂ * log(N)). [
[9,9,4],
[6,6,8],
116.2 Java Solution 2 - Optimized Disjoint Set [2,1,1]
]
Output: 4
class Solution { Explanation: The longest increasing path is [1, 2, 6, 9].
public int removeStones(int[][] stones) {
DisjointSet ds = new DisjointSet(20000);
for(int[] stone: stones){
ds.union(stone[0], stone[1]+10000); 117.1 Java Solution 1 - Naive DFS
}

HashSet<Integer> set = new HashSet<>(); public int longestIncreasingPath(int[][] matrix) {


for(int[] stone: stones){ if(matrix==null||matrix.length==0||matrix[0].length==0)
set.add(ds.find(stone[0])); return 0;
}
int[] max = new int[1];
return stones.length - set.size(); for(int i=0; i<matrix.length; i++) {
} for(int j=0; j<matrix[0].length; j++){
} dfs(matrix, i, j, max, 1);
}
class DisjointSet{ }
int[] parent;
public DisjointSet(int size){ return max[0];
parent = new int[size]; }
for(int i=0; i<size; i++){
parent[i] = i; public void dfs(int[][] matrix, int i, int j, int[] max, int len){
}
} max[0]=Math.max(max[0], len);

public void union(int i, int j){ int m=matrix.length;


parent[find(i)] = find(j); int n=matrix[0].length;
}
int[] dx={-1, 0, 1, 0};
public int find(int i){ int[] dy={0, 1, 0, -1};
while(parent[i] != i){
i = parent[i]; for(int k=0; k<4; k++){
} int x = i+dx[k];
int y = j+dy[k];
return i;
} if(x>=0 && x<m && y>=0 && y<n && matrix[x][y]>matrix[i][j]){
} dfs(matrix, x, y, max, len+1);
}

Program Creek 211 | 568 Program Creek 212 | 568 213 | 568
117 Longest Increasing Path in a Matrix 117 Longest Increasing Path in a Matrix

}
}

This naive DFS solution’s time complexity is O(m*n*4ˆ(m+n)).


118 Word Search
117.2 Java Solution 2- Optimization with memorization
Given a 2D board and a word, find if the word exists in the grid.
A common approach to improve DFS is through memorization.
The word can be constructed from letters of sequentially adjacent cell, where "adjacent" cells are those horizon-
public int longestIncreasingPath(int[][] matrix) { tally or vertically neighboring. The same letter cell may not be used more than once.
if (matrix == null || matrix.length == 0 || matrix[0].length == 0) { For example, given board =
return 0;
} [
["ABCE"],
int result = 0; ["SFCS"],
int m = matrix.length; ["ADEE"]
int n = matrix[0].length; ]

int[][] mem = new int[m][n]; word = "ABCCED", ->returns true, word = "SEE", ->returns true, word = "ABCB", ->returns false.
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
int t = helper(matrix, mem, i, j); 118.1 Java Solution
result = Math.max(result, t);
} This problem can be solve by using a typical DFS algorithm.
}
public boolean exist(char[][] board, String word) {
return result; int m = board.length;
} int n = board[0].length;

private int helper(int[][] matrix, int[][] mem, int i, int j) { boolean result = false;
if (mem[i][j] > 0) { for(int i=0; i<m; i++){
return mem[i][j]; for(int j=0; j<n; j++){
} if(dfs(board,word,i,j,0)){
result = true;
int[] dx = {-1, 0, 1, 0}; }
int[] dy = {0, 1, 0, -1}; }
}
for (int k = 0; k < 4; k++) {
int x = i + dx[k]; return result;
int y = j + dy[k]; }

if (x >= 0 && y >= 0 public boolean dfs(char[][] board, String word, int i, int j, int k){
&& x < matrix.length int m = board.length;
&& y < matrix[0].length int n = board[0].length;
&& matrix[x][y] > matrix[i][j]) {
mem[i][j] = Math.max(mem[i][j], helper(matrix, mem, x, y)); if(i<0 || j<0 || i>=m || j>=n){
} return false;
} }

return ++mem[i][j]; if(board[i][j] == word.charAt(k)){


} char temp = board[i][j];
board[i][j]=’#’;
if(k==word.length()-1){
Because of the memorization matrix, the upper bound time complexity of the DFS is O(m*n). With the loop in
return true;
the main method, the overall time complexity is O(m2̂ * n2̂)
}else if(dfs(board, word, i-1, j, k+1)
||dfs(board, word, i+1, j, k+1)
||dfs(board, word, i, j-1, k+1)

Program Creek 214 | 568 Program Creek 215 | 568 216 | 568
118 Word Search 118 Word Search

||dfs(board, word, i, j+1, k+1)){ if(k>=word.length()-1){


return true; return true;
} }
board[i][j]=temp;
} int[] di={-1,0,1,0};
int[] dj={0,1,0,-1}; 119 Word Search II
return false;
} char t = board[i][j];
board[i][j]=’#’; Given a 2D board and a list of words from the dictionary, find all words in the board.
Each word must be constructed from letters of sequentially adjacent cell, where "adjacent" cells are those
for(int m=0; m<4; m++){ horizontally or vertically neighboring. The same letter cell may not be used more than once in a word.
int pi=i+di[m]; For example, given words = ["oath","pea","eat","rain"] and board =
int pj=j+dj[m];
if(pi>=0&&pi<board.length&&pj>=0&&pj<board[0].length&&board[pi][pj]==word.charAt(k+1)){ [
if(dfs(board,word,pi,pj,k+1)){ [’o’,’a’,’a’,’n’],
return true; [’e’,’t’,’a’,’e’],
} [’i’,’h’,’k’,’r’],
} [’i’,’f’,’l’,’v’]
} ]

board[i][j]=t; Return ["eat","oath"].

return false;
} 119.1 Java Solution 1
Similar to Word Search, this problem can be solved by DFS. However, this solution exceeds time limit.

public List<String> findWords(char[][] board, String[] words) {


ArrayList<String> result = new ArrayList<String>();

int m = board.length;
int n = board[0].length;

for (String word : words) {


boolean flag = false;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
char[][] newBoard = new char[m][n];
for (int x = 0; x < m; x++)
for (int y = 0; y < n; y++)
Similarly, below is another way of writing this algorithm. newBoard[x][y] = board[x][y];

public boolean exist(char[][] board, String word) {


if (dfs(newBoard, word, i, j, 0)) {
for(int i=0; i<board.length; i++){
flag = true;
for(int j=0; j<board[0].length; j++){
}
if(dfs(board, word, i, j, 0)){
}
return true;
}
}
if (flag) {
}
result.add(word);
}
}
}
return false;
}
return result;
}
public boolean dfs(char[][] board, String word, int i, int j, int k){
if(board[i][j]!=word.charAt(k)){
public boolean dfs(char[][] board, String word, int i, int j, int k) {
return false;
int m = board.length;
}
int n = board[0].length;

Program Creek 217 | 568 Program Creek 218 | 568 219 | 568
119 Word Search II 119 Word Search II 119 Word Search II

public void dfs(char[][] board, boolean[][] visited, String str, int i, int j, Trie trie){ if(node.item.equals(word)){
if (i < 0 || j < 0 || i >= m || j >= n || k > word.length() - 1) { int m=board.length; return true;
return false; int n=board[0].length; }else{
} return false;
if(i<0 || j<0||i>=m||j>=n){ }
if (board[i][j] == word.charAt(k)) { return; }
char temp = board[i][j]; }
board[i][j] = ’#’; public boolean startsWith(String prefix){
if(visited[i][j]) TrieNode node = root;
if (k == word.length() - 1) { return; for(char c: prefix.toCharArray()){
return true; if(node.children[c-’a’]==null)
} else if (dfs(board, word, i - 1, j, k + 1) str = str + board[i][j]; return false;
|| dfs(board, word, i + 1, j, k + 1) node = node.children[c-’a’];
|| dfs(board, word, i, j - 1, k + 1) if(!trie.startsWith(str)) }
|| dfs(board, word, i, j + 1, k + 1)) { return; return true;
board[i][j] = temp; }
return true; if(trie.search(str)){ }
} result.add(str);
}
} else {
return false; visited[i][j]=true;
} dfs(board, visited, str, i-1, j, trie);
dfs(board, visited, str, i+1, j, trie);
return false; dfs(board, visited, str, i, j-1, trie);
} dfs(board, visited, str, i, j+1, trie);
visited[i][j]=false;
}
}
119.2 Java Solution 2 - Trie
If the current candidate does not exist in all words’ prefix, we can stop backtracking immediately. This can be //Trie Node
class TrieNode{
done by using a trie structure.
public TrieNode[] children = new TrieNode[26];
public class Solution { public String item = "";
Set<String> result = new HashSet<String>(); }

public List<String> findWords(char[][] board, String[] words) { //Trie


//HashSet<String> result = new HashSet<String>(); class Trie{
public TrieNode root = new TrieNode();
Trie trie = new Trie();
for(String word: words){ public void insert(String word){
trie.insert(word); TrieNode node = root;
} for(char c: word.toCharArray()){
if(node.children[c-’a’]==null){
int m=board.length; node.children[c-’a’]= new TrieNode();
int n=board[0].length; }
node = node.children[c-’a’];
boolean[][] visited = new boolean[m][n]; }
node.item = word;
for(int i=0; i<m; i++){ }
for(int j=0; j<n; j++){
dfs(board, visited, "", i, j, trie); public boolean search(String word){
} TrieNode node = root;
} for(char c: word.toCharArray()){
if(node.children[c-’a’]==null)
return new ArrayList<String>(result); return false;
} node = node.children[c-’a’];
}

Program Creek 220 | 568 Program Creek 221 | 568 Program Creek 222 | 568
120 Number of Islands 120 Number of Islands

merge(grid, i, j+1); }
}
return i;
}

120 Number of Islands 120.2 Java Solution 2 - Union-Find Check out Number of Island II.

Time is O(m*n*log(k)).
Given a 2-d grid map of ’1’s (land) and ’0’s (water), count the number of islands. An island is surrounded by
water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of public int numIslands(char[][] grid) {
the grid are all surrounded by water. if(grid==null || grid.length==0 || grid[0].length==0)
Example 1: return 0;

11110 int m = grid.length;


11010 int n = grid[0].length;
11000
00000 int[] dx={-1, 1, 0, 0};
int[] dy={0, 0, -1, 1};
Answer: 1
int[] root = new int[m*n];

120.1 Java Solution 1 - DFS int count=0;


for(int i=0; i<m; i++){
The basic idea of the following solution is merging adjacent lands, and the merging should be done recursively. for(int j=0; j<n; j++){
Each element is visited once only. So time is O(m*n). if(grid[i][j]==’1’){
root[i*n+j] = i*n+j;
public int numIslands(char[][] grid) { count++;
if(grid==null || grid.length==0||grid[0].length==0) }
return 0; }
}
int m = grid.length;
int n = grid[0].length; for(int i=0; i<m; i++){
for(int j=0; j<n; j++){
int count=0; if(grid[i][j]==’1’){
for(int i=0; i<m; i++){ for(int k=0; k<4; k++){
for(int j=0; j<n; j++){ int x = i+dx[k];
if(grid[i][j]==’1’){ int y = j+dy[k];
count++;
merge(grid, i, j); if(x>=0&&x<m&&y>=0&&y<n&&grid[x][y]==’1’){
} int cRoot = getRoot(root, i*n+j);
} int nRoot = getRoot(root, x*n+y);
} if(nRoot!=cRoot){
root[cRoot]=nRoot; //update previous node’s root to be current
return count; count--;
} }

public void merge(char[][] grid, int i, int j){ }


int m=grid.length; }
int n=grid[0].length; }
}
if(i<0||i>=m||j<0||j>=n||grid[i][j]!=’1’) }
return;
return count;
grid[i][j]=’X’; }

merge(grid, i-1, j); public int getRoot(int[] arr , int i){


merge(grid, i+1, j); while(arr[i]!=i){
merge(grid, i, j-1); i = arr[arr[i]];

223 | 568 Program Creek 224 | 568 Program Creek 225 | 568
121 Find a Path in a Matrix

list.clear();
list.addAll(temp);
return;
}

121 Find a Path in a Matrix int[] dx = {-1, 0, 1, 0}; 122 Sudoku Solver
int[] dy = {0, 1, 0, -1};

Given a 2d matrix, find a path from the top left corner to bottom right corner. Assume there exists at least one for(int k=0; k<4; k++){ Write a program to solve a Sudoku puzzle by filling the empty cells.
path, and you only need to find one valid path. You can move up, right, down, left at any position. int x = i+dx[k];
For example, given int y = j+dy[k];
122.1 Java Solution
[1, 0, 0, 0, 0] if(x>=0&&y>=0&&x<=m-1&&y<=m-1 && matrix[x][y]==1){
[1, 0, 1, 1, 1] temp.add(new int[]{x,y});
[1, 1, 1, 0, 1] public void solveSudoku(char[][] board) {
int prev = matrix[x][y];
[1, 0, 0, 0, 1] helper(board);
matrix[x][y]=0;
[1, 0, 0, 0, 1] }

dfs(matrix, x, y, temp, list);


A valid path is private boolean helper(char[][] board){
for(int i=0; i<9; i++){
matrix[x][y]=prev;
[1, 0, 0, 0, 0] for(int j=0; j<9; j++){
temp.remove(temp.size()-1);
[1, 0, 1, 1, 1] if(board[i][j]!=’.’){
}
[1, 1, 1, 0, 1] continue;
}
[0, 0, 0, 0, 1] }
}
[0, 0, 0, 0, 1]
for(char k=’1’; k<=’9’; k++){
board[i][j]=k;
if(isValid(board, i, j) && helper(board)){
121.1 Java Solution return true;
}
board[i][j]=’.’;
public int[][] findPath(int[][] matrix){ }
int m = matrix.length;
return false;
int[][] result = new int[m][m]; }
}
ArrayList<int[]> temp = new ArrayList<int[]>();
ArrayList<int[]> list = new ArrayList<int[]>(); return true; //return true if all cells are checked
}
dfs(matrix, 0, 0, temp, list);
private boolean isValid(char[][] board, int i, int j){
HashSet<Character> set = new HashSet<>();
for(int i=0; i<list.size(); i++){
result[list.get(i)[0]][list.get(i)[1]]=1; for(int k=0; k<9; k++){
//System.out.println(Arrays.toString(list.get(i))); if(set.contains(board[i][k])){
} return false;
}
result[0][0]=1; if(board[i][k]!=’.’){
set.add(board[i][k]);
return result; }
}
}
public void dfs(int[][] matrix, int i, int j,
ArrayList<int[]> temp, ArrayList<int[]> list){ set.clear();

int m=matrix.length; for(int k=0; k<9; k++){


if(set.contains(board[k][j])){
if(i==m-1 && j==m-1){ return false;

226 | 568 Program Creek 227 | 568 228 | 568


122 Sudoku Solver 122 Sudoku Solver

} private boolean isValid(char[][] board, int row, int col, char c) {


if(board[k][j]!=’.’){ for (int i = 0; i < 9; i++) {
set.add(board[k][j]); if (board[i][col] != ’.’ && board[i][col] == c) {
} return false;
} }
123 Valid Sudoku
set.clear(); if (board[row][i] != ’.’ && board[row][i] == c) {
return false;
int x=i/3 * 3; } Determine if a Sudoku is valid. The Sudoku board could be partially filled, where empty cells are filled with the
int y=j/3 * 3; character ’.’.
for(int m=x; m<x+3; m++){ if (board[3 * (row / 3) + i / 3][3 * (col / 3) + i % 3] != ’.’
for(int n=y; n<y+3; n++){ &&
if(set.contains(board[m][n])){ board[3 * (row / 3) + i / 3][3 * (col / 3) + i % 3] == c) {
return false; return false;
} }
if(board[m][n]!=’.’){ }
set.add(board[m][n]); return true;
} }
}
} The time complexity is O(9m̂) where m represents the number of blanks to be filled. No extra space is needed.

set.clear();

return true;
}

122.2 Improved Version

public void solveSudoku(char[][] board) {


helper(board);
123.1 Java Solution
}

private boolean helper(char[][] board) { public boolean isValidSudoku(char[][] board) {


for (int i = 0; i < 9; i++) { if (board == null || board.length != 9 || board[0].length != 9)
for (int j = 0; j < 9; j++) { return false;
if (board[i][j] != ’.’) { // check each column
continue; for (int i = 0; i < 9; i++) {
} boolean[] m = new boolean[9];
for (int j = 0; j < 9; j++) {
for (char k = ’1’; k <= ’9’; k++) { if (board[i][j] != ’.’) {
if (isValid(board, i, j, k)) { if (m[(int) (board[i][j] - ’1’)]) {
board[i][j] = k; return false;
if (helper(board)) { }
return true; m[(int) (board[i][j] - ’1’)] = true;
} }
board[i][j] = ’.’; }
} }
}
return false; //check each row
} for (int j = 0; j < 9; j++) {
} boolean[] m = new boolean[9];
for (int i = 0; i < 9; i++) {
return true; //return true if all cells are checked if (board[i][j] != ’.’) {
} if (m[(int) (board[i][j] - ’1’)]) {
return false;

Program Creek 229 | 568 Program Creek 230 | 568 231 | 568
123 Valid Sudoku 124 Walls and Gates

} int m = rooms.length;
m[(int) (board[i][j] - ’1’)] = true; int n = rooms[0].length;
}
} for(int i=0; i<m; i++){
} for(int j=0; j<n; j++){
124 Walls and Gates if(rooms[i][j]==0){
//check each 3*3 matrix fill(rooms, i, j, 0);
for (int block = 0; block < 9; block++) { }
boolean[] m = new boolean[9]; 124.1 Java Solution 1 - DFS }
for (int i = block / 3 * 3; i < block / 3 * 3 + 3; i++) { }
for (int j = block % 3 * 3; j < block % 3 * 3 + 3; j++) { }
if (board[i][j] != ’.’) { public void wallsAndGates(int[][] rooms) {
if (m[(int) (board[i][j] - ’1’)]) { if(rooms==null || rooms.length==0||rooms[0].length==0) public void fill(int[][] rooms, int i, int j, int distance){
return false; return; int m=rooms.length;
} int n=rooms[0].length;
m[(int) (board[i][j] - ’1’)] = true; int m = rooms.length;
} int n = rooms[0].length; if(i<0||i>=m||j<0||j>=n||rooms[i][j]<distance){
} return;
} boolean[][] visited = new boolean[m][n]; }
}
for(int i=0; i<m; i++){ rooms[i][j] = distance;
return true; for(int j=0; j<n; j++){
} if(rooms[i][j]==0){ fill(rooms, i-1, j, distance+1);
fill(rooms, i-1, j, 0, visited); fill(rooms, i, j+1, distance+1);
fill(rooms, i, j+1, 0, visited); fill(rooms, i+1, j, distance+1);
fill(rooms, i+1, j, 0, visited); fill(rooms, i, j-1, distance+1);
fill(rooms, i, j-1, 0, visited); }
visited = new boolean[m][n];
}
}
} 124.2 Java Solution 2 - BFS
}

public void fill(int[][] rooms, int i, int j, int start, boolean[][] visited){ public void wallsAndGates(int[][] rooms) {
int m=rooms.length; if(rooms==null || rooms.length==0||rooms[0].length==0)
int n=rooms[0].length; return;

if(i<0||i>=m||j<0||j>=n||rooms[i][j]<=0||visited[i][j]){ int m = rooms.length;


return; int n = rooms[0].length;
}
LinkedList<Integer> queue = new LinkedList<Integer>();
rooms[i][j] = Math.min(rooms[i][j], start+1);
visited[i][j]=true; for(int i=0; i<m; i++){
for(int j=0; j<n; j++){
fill(rooms, i-1, j, start+1, visited); if(rooms[i][j]==0){
fill(rooms, i, j+1, start+1, visited); queue.add(i*n+j);
fill(rooms, i+1, j, start+1, visited); }
fill(rooms, i, j-1, start+1, visited); }
}
visited[i][j]=false;
} while(!queue.isEmpty()){
int head = queue.poll();
The DFS solution can be simplified as the following: int x=head/n;
int y=head%n;
public void wallsAndGates(int[][] rooms) {
if(rooms==null || rooms.length==0||rooms[0].length==0) if(x>0 && rooms[x-1][y]==Integer.MAX_VALUE){
return; rooms[x-1][y]=rooms[x][y]+1;
queue.add((x-1)*n+y);

Program Creek 232 | 568 233 | 568 Program Creek 234 | 568
124 Walls and Gates 125 Surrounded Regions

} }

if(x<m-1 && rooms[x+1][y]==Integer.MAX_VALUE){ if(board[m-1][j] == ’O’){


rooms[x+1][y]=rooms[x][y]+1; merge(board, m-1, j);
queue.add((x+1)*n+y); }
} 125 Surrounded Regions }

if(y>0 && rooms[x][y-1]==Integer.MAX_VALUE){ //process the board


rooms[x][y-1]=rooms[x][y]+1; Given a 2D board containing ’X’ and ’O’, capture all regions surrounded by ’X’. A region is captured by flipping for(int i=0;i<m;i++){
queue.add(x*n+y-1); all ’O’s into ’X’s in that surrounded region. for(int j=0; j<n; j++){
} For example, if(board[i][j] == ’O’){
board[i][j] = ’X’;
if(y<n-1 && rooms[x][y+1]==Integer.MAX_VALUE){ X X X X }else if(board[i][j] == ’#’){
rooms[x][y+1]=rooms[x][y]+1; X O O X board[i][j] = ’O’;
queue.add(x*n+y+1); X X O X }
} X O X X }
} }
} After running your function, the board should be: }

X X X X public void merge(char[][] board, int i, int j){


X X X X board[i][j] = ’#’;
X X X X
X O X X int[] dx = {-1, 0, 1, 0};
int[] dy = {0, 1, 0, -1};

for(int k=0; k<4; k++){


125.1 Analysis int x = i+dx[k];
int y = j+dy[k];
This problem is similar to Number of Islands. In this problem, only the cells on the boarders can not be sur-
rounded. So we can first merge those O’s on the boarders like in Number of Islands and replace O’s with ’#’, and if(x>=0 && x<board.length
then scan the board and replace all O’s left (if any). && y>=0 && y<board[0].length
&& board[x][y]==’O’){
merge(board, x, y);
125.2 Depth-first Search }
}
}
public void solve(char[][] board) {
if(board == null || board.length==0)
return;
125.3 Breath-first Search
int m = board.length;
int n = board[0].length; We can also use a queue to do breath-first search for this problem.
//merge O’s on left & right boarder public void solve(char[][] board) {
for(int i=0;i<m;i++){ if(board==null || board.length==0 || board[0].length==0)
if(board[i][0] == ’O’){ return;
merge(board, i, 0);
} int m=board.length;
int n=board[0].length;
if(board[i][n-1] == ’O’){
merge(board, i, n-1);
} for(int j=0; j<n; j++){
} if(board[0][j]==’O’){
bfs(board, 0, j);
//merge O’s on top & bottom boarder }
for(int j=0; j<n; j++){ }
if(board[0][j] == ’O’){
merge(board, 0, j); for(int j=0; j<n; j++){

Program Creek 235 | 568 236 | 568 Program Creek 237 | 568
125 Surrounded Regions 125 Surrounded Regions

if(board[m-1][j]==’O’){ }
bfs(board, m-1, j); }
} }
}

for(int i=0; i<m; i++){ 126 Set Matrix Zeroes


if(board[i][0]==’O’){
bfs(board, i, 0);
} Given a m * n matrix, if an element is 0, set its entire row and column to 0. Do it in place.
}

for(int i=0; i<m; i++){ 126.1 Analysis


if(board[i][n-1]==’O’){
bfs(board, i, n-1); This problem should be solved in place, i.e., no other array should be used. We can use the first column and the
} first row to track if a row/column should be set to 0.
} Since we used the first row and first column to mark the zero row/column, the original values are changed.

for(int i=0; i<m; i++){


for(int j=0; j<n; j++){
if(board[i][j]==’O’){
board[i][j]=’X’;
}
if(board[i][j]==’1’){
board[i][j]=’O’;
}
}
}
}

public void bfs(char[][] board, int o, int p){


int m=board.length;
int n=board[0].length;

int index = o*n+p;


LinkedList<Integer> queue = new LinkedList<Integer>(); Step 1: First row contains zero = true; First column contains zero = false;
queue.offer(index);
board[o][p]=’1’;

while(!queue.isEmpty()){
int top = queue.poll();
int i=top/n;
int j=top%n;

if(i-1>=0 && board[i-1][j]==’O’){


board[i-1][j]=’1’;
queue.offer((i-1)*n+j);
}
if(i+1<m && board[i+1][j]==’O’){
board[i+1][j]=’1’;
queue.offer((i+1)*n+j);
}
if(j-1>=0 && board[i][j-1]==’O’){
board[i][j-1]=’1’;
queue.offer(i*n+j-1);
}
if(j+1<n && board[i][j+1]==’O’){
board[i][j+1]=’1’;
queue.offer(i*n+j+1);

Program Creek 238 | 568 Program Creek 239 | 568 240 | 568
126 Set Matrix Zeroes 126 Set Matrix Zeroes

for(int i=1; i<matrix.length; i++){


for(int j=1; j<matrix[0].length; j++){
if(matrix[i][j] == 0){
matrix[i][0] = 0;
matrix[0][j] = 0;
} 127 Spiral Matrix
}
}
Given a matrix of m x n elements (m rows, n columns), return all elements of the matrix in spiral order.
//use mark to set elements For example, given the following matrix:
for(int i=1; i<matrix.length; i++){
for(int j=1; j<matrix[0].length; j++){ [
if(matrix[i][0] == 0 || matrix[0][j] == 0){ [ 1, 2, 3 ],
matrix[i][j] = 0; [ 4, 5, 6 ],
} [ 7, 8, 9 ]
} ]
}
You should return [1,2,3,6,9,8,7,4,5].
//set first column and row
if(firstColumnZero){
for(int i=0; i<matrix.length; i++) 127.1 Java Solution 1
matrix[i][0] = 0;
} If more than one row and column left, it can form a circle and we process the circle. Otherwise, if only one row
or column left, we process that column or row ONLY.
if(firstRowZero){
for(int i=0; i<matrix[0].length; i++) public class Solution {
matrix[0][i] = 0; public ArrayList<Integer> spiralOrder(int[][] matrix) {
} ArrayList<Integer> result = new ArrayList<Integer>();

} if(matrix == null || matrix.length == 0) return result;


}
int m = matrix.length;
int n = matrix[0].length;

126.2 Java Solution int x=0;


int y=0;

public class Solution { while(m>0 && n>0){


public void setZeroes(int[][] matrix) {
boolean firstRowZero = false; //if one row/column left, no circle can be formed
boolean firstColumnZero = false; if(m==1){
for(int i=0; i<n; i++){
//set first row and column zero or not result.add(matrix[x][y++]);
for(int i=0; i<matrix.length; i++){ }
if(matrix[i][0] == 0){ break;
firstColumnZero = true; }else if(n==1){
break; for(int i=0; i<m; i++){
} result.add(matrix[x++][y]);
} }
break;
for(int i=0; i<matrix[0].length; i++){ }
if(matrix[0][i] == 0){
firstRowZero = true; //below, process a circle
break;
} //top - move right
} for(int i=0;i<n-1;i++){
result.add(matrix[x][y++]);
//mark zeros on first row and column }

Program Creek 241 | 568 Program Creek 242 | 568 243 | 568
127 Spiral Matrix 127 Spiral Matrix 127 Spiral Matrix

} }
//right - move down bottom--; }
for(int i=0;i<m-1;i++){
result.add(matrix[x++][y]); // prevent duplicate column //left - move up
} if(right<left) if(n>1){
break; for(int i=0;i<m-1;i++){
//bottom - move left result.add(matrix[x--][y]);
for(int i=0;i<n-1;i++){ for(int i=bottom; i>=top; i--){ }
result.add(matrix[x][y--]); result.add(matrix[i][left]); }
} }
left++; if(m==1||n==1)
//left - move up } result.addAll(spiralOrder(matrix, x, y, 1, 1));
for(int i=0;i<m-1;i++){ else
result.add(matrix[x--][y]); return result; result.addAll(spiralOrder(matrix, x+1, y+1, m-2, n-2));
} }
return result;
x++; }
y++; }
m=m-2; 127.2 Java Solution 2
n=n-2;
} We can also recursively solve this problem. The solution’s performance is not better than Solution 1. Therefore,
Solution 1 should be preferred.
return result;
} public class Solution {
} public ArrayList<Integer> spiralOrder(int[][] matrix) {
if(matrix==null || matrix.length==0)
Similarly, we can write the solution this way: return new ArrayList<Integer>();

public List<Integer> spiralOrder(int[][] matrix) { return spiralOrder(matrix,0,0,matrix.length,matrix[0].length);


List<Integer> result = new ArrayList<Integer>(); }
if(matrix==null||matrix.length==0||matrix[0].length==0)
return result;
public ArrayList<Integer> spiralOrder(int [][] matrix, int x, int y, int m, int n){
int m = matrix.length; ArrayList<Integer> result = new ArrayList<Integer>();
int n = matrix[0].length;
if(m<=0||n<=0)
int left=0; return result;
int right=n-1;
int top = 0; //only one element left
int bottom = m-1; if(m==1&&n==1) {
result.add(matrix[x][y]);
while(result.size()<m*n){ return result;
for(int j=left; j<=right; j++){ }
result.add(matrix[top][j]);
} //top - move right
top++; for(int i=0;i<n-1;i++){
result.add(matrix[x][y++]);
for(int i=top; i<=bottom; i++){ }
result.add(matrix[i][right]);
} //right - move down
right--; for(int i=0;i<m-1;i++){
result.add(matrix[x++][y]);
//prevent duplicate row }
if(bottom<top)
break; //bottom - move left
if(m>1){
for(int j=right; j>=left; j--){ for(int i=0;i<n-1;i++){
result.add(matrix[bottom][j]); result.add(matrix[x][y--]);

Program Creek 244 | 568 Program Creek 245 | 568 Program Creek 246 | 568
128 Spiral Matrix II

i++;
result[x][y]=i;
x--;
}
x++;
128 Spiral Matrix II y++; 129 Rotate Image
}

Given an integer n, generate a square matrix filled with elements from 1 to n2̂ in spiral order. For example, given return result; You are given an n x n 2D matrix representing an image.
n = 4, } Rotate the image by 90 degrees (clockwise).
Follow up: Could you do this in-place?
[
[1, 2, 3, 4],
[12, 13, 14, 5],
[11, 16, 15, 6],
128.2 Java Solution 2 129.1 In-place Solution
[10, 9, 8, 7]
By using the relation "matrix[i][j] = matrix[n-1-j][i]", we can loop through the matrix.
] public int[][] generateMatrix(int n) {
int[][] result = new int[n][n]; public void rotate(int[][] matrix) {
int n = matrix.length;
int k=1; for (int i = 0; i < n / 2; i++) {
128.1 Java Solution 1 int top=0; for (int j = 0; j < Math.ceil(((double) n) / 2.); j++) {
int bottom=n-1; int temp = matrix[i][j];
int left=0; matrix[i][j] = matrix[n-1-j][i];
public int[][] generateMatrix(int n) {
int right=n-1; matrix[n-1-j][i] = matrix[n-1-i][n-1-j];
int total = n*n;
matrix[n-1-i][n-1-j] = matrix[j][n-1-i];
int[][] result= new int[n][n];
while(k<=n*n){ matrix[j][n-1-i] = temp;
for(int i=left; i<=right; i++){ }
int x=0;
result[top][i]=k; }
int y=0;
k++; }
int step = 0;
}
top++;
for(int i=0;i<total;){
while(y+step<n){
for(int i=top; i<=bottom; i++){
i++;
result[i][right]=k;
result[x][y]=i;
k++;
y++;
}
right--;
}
y--;
for(int i=right; i>=left; i--){
x++;
result[bottom][i]=k;
k++;
while(x+step<n){
}
i++;
bottom--;
result[x][y]=i;
x++;
for(int i=bottom; i>=top; i--){
}
result[i][left] = k;
x--;
k++;
y--;
}
left++;
while(y>=0+step){
}
i++;
result[x][y]=i;
return result;
y--;
}
}
y++;
x--;
step++;

while(x>=0+step){

247 | 568 Program Creek 248 | 568 249 | 568


130 Range Sum Query 2D Immutable 130 Range Sum Query 2D Immutable

[Pleaseinsert\PrerenderUnicode{âĂŞ}intopreamble]-Immutable.png
public NumMatrix(int[][] matrix) {
if(matrix==null || matrix.length==0||matrix[0].length==0)
return;

130 Range Sum Query 2D Immutable int m = matrix.length;


int n = matrix[0].length;
sum = new int[m][n];
Given a 2D matrix matrix, find the sum of the elements inside the rectangle defined by its upper left corner (row1,
col1) and lower right corner (row2, col2). for(int i=0; i<m; i++){
int sumRow=0;
for(int j=0; j<n; j++){
130.1 Analysis if(i==0){
sumRow += matrix[i][j];
Since the assumption is that there are many calls to sumRegion method, we should use some extra space to store sum[i][j]=sumRow;
the intermediate results. }else{
The solution is similar to other sum related problems such as . The basic idea is demonstrated in the following sumRow += matrix[i][j];
example: sum[i][j]=sumRow+sum[i-1][j];
}

}
}
}

public int sumRegion(int row1, int col1, int row2, int col2) {
./figures/Range-Sum-Query-2D-\begingroup \let \relax \relax \endgroup [Pleaseinsert\PrerenderUnicode{âĂŞ}intopreamble]-Immutable.png
if(this.sum==null)
return 0;

int topRightX = row1;


int topRightY = col2;

int bottomLeftX=row2;
int bottomLeftY= col1;

int result=0;

if(row1==0 && col1==0){


result = sum[row2][col2];
}else if(row1==0){
result = sum[row2][col2]
-sum[bottomLeftX][bottomLeftY-1];

}else if(col1==0){
result = sum[row2][col2]
-sum[topRightX-1][topRightY];
}else{
result = sum[row2][col2]
-sum[topRightX-1][topRightY]
-sum[bottomLeftX][bottomLeftY-1]
+sum[row1-1][col1-1];
}
Here we define an array sum[][] which stores the sum value from (0,0) to the current cell.
return result;
}
130.2 Java Solution }

public class NumMatrix {


int [][] sum;

250 | 568 Program Creek 251 | 568 Program Creek 252 | 568
131 Shortest Distance from All Buildings

return result == Integer.MAX_VALUE ? -1 : result;


}

131 Shortest Distance from All Buildings public void bfs(int[][] grid, int ox, int oy, int i, int j, 132 Best Meeting Point
int distanceSoFar, boolean[][] visited, LinkedList<Integer> queue){

You want to build a house on an empty land which reaches all buildings in the shortest amount of distance. You visit(grid, i, j, i, j, distanceSoFar, visited, queue); A group of two or more people wants to meet and minimize the total travel distance. You are given a 2D grid of
can only move up, down, left and right. You are given a 2D grid of values 0, 1 or 2, where: int n = grid[0].length; values 0 or 1, where each 1 marks the home of someone in the group. The distance is calculated using Manhattan
Each 0 marks an empty land which you can pass by freely. Each 1 marks a building which you cannot pass Distance, where distance(p1, p2) = |p2.x - p1.x| + |p2.y - p1.y|.
through. Each 2 marks an obstacle which you cannot pass through. while(!queue.isEmpty()){ For example, given three people living at (0,0), (0,4), and (2,2):
For example, given three buildings at (0,0), (0,4), (2,2), and an obstacle at (0,2). The point (1,2) is an ideal empty int size = queue.size();
distanceSoFar++; 1 - 0 - 0 - 0 - 1
land to build a house, as the total travel distance of 3+3+1=7 is minimal. So return 7.
| | | | |
for(int k=0; k<size; k++){ 0 - 0 - 0 - 0 - 0
| | | | |
131.1 Java Solution int top = queue.poll();
i=top/n; 0 - 0 - 1 - 0 - 0

This problem can be solve by BFS. We define one matrix for tracking the distance from each building, and another j=top%n;

matrix for tracking the number of buildings which can be reached. The point (0,2) is an ideal meeting point, as the total travel distance of 2+2+2=6 is minimal. So return 6.
visit(grid, ox, oy, i-1, j, distanceSoFar, visited, queue);
public class Solution { visit(grid, ox, oy, i+1, j, distanceSoFar, visited, queue);
visit(grid, ox, oy, i, j-1, distanceSoFar, visited, queue); 132.1 Java Solution
int[][] numReach; visit(grid, ox, oy, i, j+1, distanceSoFar, visited, queue);
int[][] distance; } This problem is converted to find the median value on x-axis and y-axis.

public int shortestDistance(int[][] grid) { } public int minTotalDistance(int[][] grid) {


if(grid==null||grid.length==0||grid[0].length==0) } int m=grid.length;
return 0; int n=grid[0].length;
public void visit(int[][] grid, int ox, int oy, int i, int j, int distanceSoFar, boolean[][] visited,
int m = grid.length; LinkedList<Integer> queue){ ArrayList<Integer> cols = new ArrayList<Integer>();
int n = grid[0].length; int m = grid.length; ArrayList<Integer> rows = new ArrayList<Integer>();
int n = grid[0].length; for(int i=0; i<m; i++){
numReach = new int[m][n]; for(int j=0; j<n; j++){
distance = new int[m][n]; if(i<0 || i>=m || j<0 || j>=n || visited[i][j]) if(grid[i][j]==1){
return; cols.add(j);
rows.add(i);
int numBuilding = 0; if((i!=ox || j!=oy) && grid[i][j]!=0){ }
for(int i=0; i<m; i++){ return; }
for(int j=0; j<n; j++){ } }
if(grid[i][j]==1){
boolean[][] visited = new boolean[m][n]; int sum=0;
LinkedList<Integer> queue = new LinkedList<Integer>(); visited[i][j]=true;
bfs(grid, i, j, i, j, 0, visited, queue); numReach[i][j]++; for(Integer i: rows){
distance[i][j]+= distanceSoFar; sum += Math.abs(i - rows.get(rows.size()/2));
numBuilding++; queue.offer(i*n+j); }
} }
} } Collections.sort(cols);
}
for(Integer i: cols){
int result=Integer.MAX_VALUE; sum+= Math.abs(i-cols.get(cols.size()/2));
for(int i=0; i<m; i++){ }
for(int j=0; j<n; j++){
if(grid[i][j] == 0 && numReach[i][j]==numBuilding){ return sum;
result = Math.min(result, distance[i][j]); }

}
}

253 | 568 Program Creek 254 | 568 255 | 568


133 Game of Life

if(count>3){
board[i][j] &=1;
}
}
}
133 Game of Life 134 TicTacToe
for(int i=0; i<m; i++){
for(int j=0; j<n; j++){
Given a board with m by n cells, each cell has an initial state live (1) or dead (0). Each cell interacts with its eight board[i][j] = board[i][j]>>1; Design a Tic-tac-toe game that is played between two players on a n x n grid.
neighbors (horizontal, vertical, diagonal) using the following four rules:
Any live cell with fewer than two live neighbors dies, as if caused by under-population. Any live cell with two }
or three live neighbors lives on to the next generation. Any live cell with more than three live neighbors dies, as } 134.1 Java Solution 1 - Naive
if by over-population.. Any dead cell with exactly three live neighbors becomes a live cell, as if by reproduction. }
Write a function to compute the next state (after one update) of the board given its current state. We can simply check the row, column and the diagonals and see if there is a winner.

public class TicTacToe {

133.1 Java Solution 1 int[][] matrix;

Because we need to solve the problem in place, we can use the higher bit to record the next state. And at the end, /** Initialize your data structure here. */
shift right a bit to get the next state for each cell. public TicTacToe(int n) {
matrix = new int[n][n];
public void gameOfLife(int[][] board) {
}
if(board==null || board.length==0||board[0].length==0)
return;
/** Player {player} makes a move at ({row}, {col}).
@param row The row of the board.
int m=board.length;
@param col The column of the board.
int n=board[0].length;
@param player The player, can be either 1 or 2.
@return The current winning condition, can be either:
int[] x = {-1, -1, 0, 1, 1, 1, 0, -1};
0: No one wins.
int[] y = {0, 1, 1, 1, 0, -1, -1, -1};
1: Player 1 wins.
2: Player 2 wins. */
for(int i=0; i<m; i++){
public int move(int row, int col, int player) {
for(int j=0; j<n; j++){
matrix[row][col]=player;
int count=0;
for(int k=0; k<8; k++){
//check row
int nx=i+x[k];
boolean win=true;
int ny=j+y[k];
for(int i=0; i<matrix.length; i++){
if(nx>=0&&nx<m&&ny>=0&&ny<n&&(board[nx][ny]&1)==1){
if(matrix[row][i]!=player){
count++;
win=false;
}
break;
}
}
}
//<2 die
if(count<2){
if(win) return player;
board[i][j] &= 1;
}
//check column
win=true;
//same state
for(int i=0; i<matrix.length; i++){
if(count==2||count==3){
if(matrix[i][col]!=player){
board[i][j] |= board[i][j]<<1;
win=false;
}
break;
}
//go live
}
if(count==3){
board[i][j] |=2;
if(win) return player;
}

//check back diagonal


//>3 die

256 | 568 Program Creek 257 | 568 258 | 568


134 TicTacToe 134 TicTacToe

win=true; dc1+=val;
for(int i=0; i<matrix.length; i++){ }
if(matrix[i][i]!=player){ if(col==n-row-1){
win=false; dc2+=val;
break; }
} 135 Sparse Matrix Multiplication
} if(Math.abs(rows[row])==n
|| Math.abs(cols[col])==n
if(win) return player; || Math.abs(dc1)==n Given two sparse matrices A and B, return the result of AB.
|| Math.abs(dc2)==n){ You may assume that A’s column number is equal to B’s row number.
//check forward diagonal return player;
win=true; }
for(int i=0; i<matrix.length; i++){ 135.1 Naive Method
if(matrix[i][matrix.length-i-1]!=player){ return 0;
win=false; } We can implement Sum(A_ik * B_kj) ->C_ij as a naive solution.
break; }
} public int[][] multiply(int[][] A, int[][] B) {
} //validity check

if(win) return player; int[][] C = new int[A.length][B[0].length];

return 0; for(int i=0; i<C.length; i++){


} for(int j=0; j<C[0].length; j++){
} int sum=0;
for(int k=0; k<A[0].length; k++){
sum += A[i][k]*B[k][j];
}
C[i][j] = sum;
134.2 Java Solution 2
}
}
public class TicTacToe {
int[] rows; return C;
int[] cols; }
int dc1;
int dc2; Time complexity is O(n3̂).
int n;
/** Initialize your data structure here. */
public TicTacToe(int n) { 135.2 Optimized Method
this.n=n;
this.rows=new int[n]; From the formula: Sum(A_ik * B_kj) ->C_ij
this.cols=new int[n]; We can see that when A_ik is 0, there is no need to compute B_kj. So we switch the inner two loops and add a
} 0-checking condition.
/** Player {player} makes a move at ({row}, {col}). public int[][] multiply(int[][] A, int[][] B) {
@param row The row of the board. //validity check
@param col The column of the board.
@param player The player, can be either 1 or 2. int[][] C = new int[A.length][B[0].length];
@return The current winning condition, can be either:
0: No one wins. for(int i=0; i<C.length; i++){
1: Player 1 wins. for(int k=0; k<A[0].length; k++){
2: Player 2 wins. */ if(A[i][k]!=0){
public int move(int row, int col, int player) { for(int j=0; j<C[0].length; j++){
int val = (player==1?1:-1); C[i][j] += A[i][k]*B[k][j];
}
rows[row]+=val; }
cols[col]+=val; }
}
if(row==col){

Program Creek 259 | 568 Program Creek 260 | 568 261 | 568
135 Sparse Matrix Multiplication 136 Add Two Numbers

return C; return fake.next;


} }

Since the matrix is sparse, time complexity is O(n2̂) which is much faster than O(n3̂). What if the digits are stored in regular order instead of reversed order?
Answer: We can simple reverse the list, calculate the result, and reverse the result.
136 Add Two Numbers
You are given two linked lists representing two non-negative numbers. The digits are stored in reverse order and
each of their nodes contain a single digit. Add the two numbers and return it as a linked list.
Input: (2 ->4 ->3) + (5 ->6 ->4) Output: 7 ->0 ->8

136.1 Java Solution

/*
2 -> 4 -> 3
5 -> 6 -> 4
7 0 8
*/
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode fake = new ListNode(0);
ListNode p = fake;

ListNode p1 = l1;
ListNode p2 = l2;

int carry = 0;
while(p1!=null || p2!=null){
int sum = carry;
if(p1!=null){
sum += p1.val;
p1 = p1.next;
}

if(p2!=null){
sum += p2.val;
p2 = p2.next;
}

if(sum>9){
carry=1;
sum = sum-10;
}else{
carry = 0;
}

ListNode l = new ListNode(sum);


p.next = l;
p = p.next;
}

//don’t forget check the carry value at the end


if(carry > 0){
ListNode l = new ListNode(carry);
p.next = l;
}

Program Creek 262 | 568 263 | 568 Program Creek 264 | 568
137 Reorder List 137 Reorder List

ListNode slow = head;


ListNode fast = head; public static void printList(ListNode n) {
System.out.println("------");
//use a fast and slow pointer to break the link to two parts. while (n != null) {
while (fast != null && fast.next != null && fast.next.next!= null) { System.out.print(n.val);
137 Reorder List //why need third/second condition? n = n.next;
System.out.println("pre "+slow.val + " " + fast.val); }
slow = slow.next; System.out.println();
Given a singly linked list L: L0→L1→ ... →Ln-1→Ln, reorder it to: L0→Ln→L1→Ln-1→L2→Ln-2→... fast = fast.next.next; }
For example, given 1,2,3,4, reorder it to 1,4,2,3. You must do this in-place without altering the nodes’ values. System.out.println("after " + slow.val + " " + fast.val); }
}

137.1 Java Solution Because the problem requires "in-place" ListNode second = slow.next;

operations, we can only change their pointers, not creating a slow.next = null;// need to close first part 137.2 Takeaway Messages
new list. This problem can be solved by doing the following 3 // now should have two lists: head and fast The three steps can be used to solve other problems of linked list. The following diagrams illustrate how each of
the steps works.
steps: // reverse order for second part Reverse List:
second = reverseOrder(second);
• Break list in the middle to two lists (use fast & slow pointers)
• Reverse the order of the second list ListNode p1 = head;
ListNode p2 = second;
• Merge two list back together
//merge two lists here
The following code is a complete runnable class with testing.
while (p2 != null) {
//Class definition of ListNode ListNode temp1 = p1.next;
class ListNode { ListNode temp2 = p2.next;
int val;
ListNode next; p1.next = p2;
p2.next = temp1;
ListNode(int x) {
val = x; p1 = temp1;
next = null; p2 = temp2;
} }
} }
}
public class ReorderList {
public static ListNode reverseOrder(ListNode head) {
public static void main(String[] args) {
ListNode n1 = new ListNode(1); if (head == null || head.next == null) {
ListNode n2 = new ListNode(2); return head;
ListNode n3 = new ListNode(3); }
ListNode n4 = new ListNode(4);
n1.next = n2; ListNode pre = head;
n2.next = n3; ListNode curr = head.next;
n3.next = n4;
while (curr != null) {
printList(n1); ListNode temp = curr.next;
curr.next = pre;
reorderList(n1); pre = curr;
curr = temp;
printList(n1); }
}
// set head node’s next
public static void reorderList(ListNode head) { head.next = null;
Merge List:
if (head != null && head.next != null) { return pre;
}

265 | 568 Program Creek 266 | 568 Program Creek 267 | 568
137 Reorder List

138 Linked List Cycle 139 Copy List with Random Pointer
Given a linked list, determine if it has a cycle in it. A linked list is given such that each node contains an additional random pointer which could point to any node
in the list or null.
Return a deep copy of the list.
138.1 Analysis
If we have 2 pointers - fast and slow. It is guaranteed that the fast one will meet the slow one if there exists a 139.1 Java Solution 1
circle.
We can solve this problem by doing the following steps:
• copy every node, i.e., duplicate every node, and insert it to the list
• copy random pointers for all newly created nodes
• break the list to two

public RandomListNode copyRandomList(RandomListNode head) {

if (head == null)
return null;

RandomListNode p = head;

// copy every node and insert to list


while (p != null) {
RandomListNode copy = new RandomListNode(p.label);
copy.next = p.next;
138.2 Java Solution p.next = copy;
p = copy.next;
}
public class Solution {
public boolean hasCycle(ListNode head) {
// copy random pointer for each new node
ListNode fast = head;
Note that pointers movements always starts with assigning the next node to a temporary variable t. p = head;
ListNode slow = head;
while (p != null) {
if (p.random != null)
while(fast != null && fast.next != null){
p.next.random = p.random.next;
slow = slow.next;
p = p.next.next;
fast = fast.next.next;
}

if(slow == fast)
// break list to two
return true;
p = head;
}
RandomListNode newHead = head.next;
while (p != null) {
return false;
RandomListNode temp = p.next;
}
p.next = temp.next;
}
if (temp.next != null)
temp.next = temp.next.next;
p = p.next;
}

return newHead;
}

Program Creek 268 | 568 269 | 568 270 | 568


139 Copy List with Random Pointer 140 Merge Two Sorted Lists

The break list part above move pointer 2 steps each time, you can also move one at a time which is simpler, like p.next = p1;
the following: p1 = p1.next;
}else{
while(p != null && p.next != null){ p.next = p2;
RandomListNode temp = p.next; p2 = p2.next;
p.next = temp.next; 140 Merge Two Sorted Lists }
p = temp; p=p.next;
} }
Merge two sorted linked lists and return it as a new list. The new list should be made by splicing together the
nodes of the first two lists. if(p1!=null){
p.next = p1;
139.2 Java Solution 2 - Using HashMap }
140.1 Analysis
From Xiaomeng’s comment below, we can use a HashMap which makes it simpler. if(p2!=null){
The key to solve the problem is defining a fake head. Then compare the first elements from each list. Add the p.next = p2;
public RandomListNode copyRandomList(RandomListNode head) { smaller one to the merged list. Finally, when one of them is empty, simply append it to the merged list, since it }
if (head == null) is already sorted.
return null; return head.next;
HashMap<RandomListNode, RandomListNode> map = new HashMap<RandomListNode, RandomListNode>(); }
RandomListNode newHead = new RandomListNode(head.label); 140.2 Java Solution
RandomListNode p = head;
RandomListNode q = newHead; public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
map.put(head, newHead); ListNode head = new ListNode(0);
ListNode p = head;
p = p.next;
while (p != null) { while(l1!=null||l2!=null){
RandomListNode temp = new RandomListNode(p.label); if(l1!=null&&l2!=null){
map.put(p, temp); if(l1.val < l2.val){
q.next = temp; p.next = l1;
q = temp; l1=l1.next;
p = p.next; }else{
} p.next=l2;
l2=l2.next;
p = head; }
q = newHead; p = p.next;
while (p != null) { }else if(l1==null){
if (p.random != null) p.next = l2;
q.random = map.get(p.random); break;
else }else if(l2==null){
q.random = null; p.next = l1;
break;
p = p.next; }
q = q.next; }
}
return head.next;
return newHead; }
}
Or write this way:

public ListNode mergeTwoLists(ListNode l1, ListNode l2) {


ListNode head = new ListNode(0);
ListNode p=head;

ListNode p1=l1;
ListNode p2=l2;
while(p1!=null && p2!=null){
if(p1.val < p2.val){

Program Creek 271 | 568 272 | 568 Program Creek 273 | 568
141 Odd Even Linked List

p1.next = p2.next;
p1 = p1.next;

p2.next = p1.next;
141 Odd Even Linked List p2 = p2.next; 142 Remove Duplicates from Sorted List
}

Given a sorted linked list, delete all duplicates such that each element appear only once.
141.1 Problem p1.next = connectNode;
For example,
Given a singly linked list, group all odd nodes together followed by the even nodes. Please note here we are return result;
} Given 1->1->2, return 1->2.
talking about the node number and not the value in the nodes. Given 1->1->2->3->3, return 1->2->3.
The program should run in O(1) space complexity and O(nodes) time complexity.
Example:

Given 1->2->3->4->5->NULL,
142.1 Thoughts
return 1->3->5->2->4->NULL.

The key of this problem is using the right loop condition. And change what is necessary in each loop. You can
use different iteration conditions like the following 2 solutions.
141.2 Analysis
142.2 Solution 1
This problem can be solved by using two pointers. We iterate over the link and move the two pointers.

/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode deleteDuplicates(ListNode head) {
if(head == null || head.next == null)
return head;

ListNode prev = head;


ListNode p = head.next;
141.3 Java Solution
while(p != null){
if(p.val == prev.val){
public ListNode oddEvenList(ListNode head) {
prev.next = p.next;
if(head == null)
p = p.next;
return head;
//no change prev
}else{
ListNode result = head;
prev = p;
ListNode p1 = head;
p = p.next;
ListNode p2 = head.next;
}
ListNode connectNode = head.next;
}

while(p1 != null && p2 != null){


return head;
ListNode t = p2.next;
}
if(t == null)
}
break;

274 | 568 Program Creek 275 | 568 276 | 568


142 Remove Duplicates from Sorted List

142.3 Solution 2

public class Solution {


public ListNode deleteDuplicates(ListNode head) {
if(head == null || head.next == null) 143 Remove Duplicates from Sorted List II 144 Partition List
return head;

ListNode p = head; Given a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinct numbers from the Given a linked list and a value x, partition it such that all nodes less than x come before nodes greater than or
original list. equal to x.
while( p!= null && p.next != null){ For example, given 1->1->1->2->3, return 2->3. You should preserve the original relative order of the nodes in each of the two partitions.
if(p.val == p.next.val){ For example, given 1->4->3->2->5->2 and x = 3, return 1->2->2->4->3->5.
p.next = p.next.next;
}else{ 143.1 Java Solution
p = p.next; 144.1 Java Solution
}
} public ListNode deleteDuplicates(ListNode head) {
ListNode t = new ListNode(0); public class Solution {
return head; t.next = head; public ListNode partition(ListNode head, int x) {
} if(head == null) return null;
} ListNode p = t;
while(p.next!=null&&p.next.next!=null){ ListNode fakeHead1 = new ListNode(0);
if(p.next.val == p.next.next.val){ ListNode fakeHead2 = new ListNode(0);
int dup = p.next.val; fakeHead1.next = head;
while(p.next!=null&&p.next.val==dup){
p.next = p.next.next; ListNode p = head;
} ListNode prev = fakeHead1;
}else{ ListNode p2 = fakeHead2;
p=p.next;
} while(p != null){
if(p.val < x){
} p = p.next;
prev = prev.next;
return t.next; }else{
}
p2.next = p;
prev.next = p.next;

p = prev.next;
p2 = p2.next;
}
}

// close the list


p2.next = null;

prev.next = fakeHead2.next;

return fakeHead1.next;
}
}

Program Creek 277 | 568 278 | 568 279 | 568


145 Intersection of Two Linked Lists

if(len1 > len2){


diff = len1-len2;
int i=0;
while(i<diff){
145 Intersection of Two Linked Lists p1 = p1.next; 146 Remove Linked List Elements
i++;
}
Remove all elements from a linked list of integers that have value val.
145.1 Problem }else{
diff = len2-len1; Example
Write a program to find the node at which the intersection of two singly linked lists begins. int i=0;
while(i<diff){ Given: 1 --> 2 --> 6 --> 3 --> 4 --> 5 --> 6, val = 6
For example, the following two linked lists: Return: 1 --> 2 --> 3 --> 4 --> 5
p2 = p2.next;
A: a1 -> a2 i++;
-> }
c1 -> c2 -> c3 }
->
146.1 Java Solution
B: b1 -> b2 -> b3 while(p1 != null && p2 != null){
if(p1.val == p2.val){ The key to solve this problem is using a helper node to track the head of the list.
begin to intersect at node c1. return p1;
public ListNode removeElements(ListNode head, int val) {
}else{
ListNode helper = new ListNode(0);
helper.next = head;
}
145.2 Java Solution ListNode p = helper;
p1 = p1.next;
p2 = p2.next;
First calculate the length of two lists and find the difference. Then start from the longer list at the diff offset, while(p.next != null){
}
iterate though 2 lists and find the node. if(p.next.val == val){
ListNode next = p.next;
/** return null;
p.next = next.next;
}
* Definition for singly-linked list. }else{
}
* public class ListNode { p = p.next;
* int val; }
* ListNode next; }
* ListNode(int x) {
* val = x; return helper.next;
* next = null; }
* }
* }
*/
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
int len1 = 0;
int len2 = 0;
ListNode p1=headA, p2=headB;
if (p1 == null || p2 == null)
return null;

while(p1 != null){
len1++;
p1 = p1.next;
}
while(p2 !=null){
len2++;
p2 = p2.next;
}

int diff = 0;
p1=headA;
p2=headB;

280 | 568 Program Creek 281 | 568 282 | 568


147 Swap Nodes in Pairs

ListNode pre = h;
while(p1!=null && p2!=null){
pre.next = p2;

ListNode t = p2.next;
147 Swap Nodes in Pairs p2.next = p1; 148 Reverse Linked List
pre = p1;
p1.next = t;
Given a linked list, swap every two adjacent nodes and return its head. Reverse a singly linked list.
For example, given 1->2->3->4, you should return the list as 2->1->4->3. p1 = p1.next;
Your algorithm should use only constant space. You may not modify the values in the list, only nodes itself can
be changed. if(t!=null) 148.1 Java Solution 1 - Iterative
p2 = t.next;
}
147.1 Java Solution 1
return h.next;
Use two template variable to track the previous and next node of each pair. }

public ListNode swapPairs(ListNode head) {


if(head == null || head.next == null)
return head;

ListNode h = new ListNode(0);


h.next = head;
ListNode p = h;

while(p.next != null && p.next.next != null){


//use t1 to track first node
ListNode t1 = p;
p = p.next;
t1.next = p.next;

//use t2 to track next node of the pair


ListNode t2 = p.next.next;
p.next.next = p; public ListNode reverseList(ListNode head) {
p.next = t2; if(head==null||head.next==null)
} return head;

return h.next; ListNode p1 = head;


} ListNode p2 = p1.next;

head.next = null;
while(p1!=null&& p2!=null){
147.2 Java Solution 2 ListNode t = p2.next;
p2.next = p1;
Each time I do the same problem I often get the different solutions. Here is another way of writing this solution. p1 = p2;
p2 = t;
public ListNode swapPairs(ListNode head) { }
if(head==null || head.next==null)
return head; return p1;
}
//a fake head
ListNode h = new ListNode(0);
h.next = head;
148.2 Java Solution 2 - Recursive
ListNode p1 = head;
ListNode p2 = head.next;
public ListNode reverseList(ListNode head) {

283 | 568 Program Creek 284 | 568 285 | 568


148 Reverse Linked List 149 Reverse Linked List II

if(head==null || head.next == null) //connect to previous part


return head; if(prev!=null)
prev.next = p1;
//get second node else
ListNode second = head.next; return p1;
//set first’s next to be null 149 Reverse Linked List II
head.next = null; return head;
}
ListNode rest = reverseList(second); Reverse a linked list from position m to n. Do it in-place and in one-pass.
second.next = head; For example: given 1->2->3->4->5->NULL, m = 2 and n = 4, return 1->4->3->2->5->NULL.

return rest;
} 149.1 Analysis

149.2 Java Solution

public ListNode reverseBetween(ListNode head, int m, int n) {


if(m==n) return head;

ListNode prev = null;//track (m-1)th node


ListNode first = new ListNode(0);//first’s next points to mth
ListNode second = new ListNode(0);//second’s next points to (n+1)th

int i=0;
ListNode p = head;
while(p!=null){
i++;
if(i==m-1){
prev = p;
}

if(i==m){
first.next = p;
}

if(i==n){
second.next = p.next;
p.next = null;
}

p= p.next;
}
if(first.next == null)
return head;

// reverse list [m, n]


ListNode p1 = first.next;
ListNode p2 = p1.next;
p1.next = second.next;

while(p1!=null && p2!=null){


ListNode t = p2.next;
p2.next = p1;
p1 = p2;
p2 = t;
}

Program Creek 286 | 568 287 | 568 Program Creek 288 | 568
150 Reverse Double Linked List

newHead= p;
p = t;
}

return newHead;
150 Reverse Double Linked List } 151 Remove Nth Node From End of List
Given a double linked list’s head node, reverse the list and return the new head node. Given a linked list, remove the nth node from the end of list and return its head.
For example, given linked list 1->2->3->4->5 and n = 2, the result is 1->2->3->5.

150.1 Java Solution


151.1 Java Solution 1 - Naive Two Passes
Calculate the length first, and then remove the nth from the beginning.

public ListNode removeNthFromEnd(ListNode head, int n) {


if(head == null)
return null;

//get length of list


ListNode p = head;
int len = 0;
while(p != null){
len++;
p = p.next;
}

//if remove first node


int fromStart = len-n+1;
if(fromStart==1)
return head.next;

//remove non-first node


p = head;
int i=0;
while(p!=null){
i++;
if(i==fromStart-1){
/* p.next = p.next.next;
* For your reference: }
* p=p.next;
* DoublyLinkedListNode { }
* int data;
* DoublyLinkedListNode next; return head;
* DoublyLinkedListNode prev; }
* }
*
*/
static DoublyLinkedListNode reverse(DoublyLinkedListNode head) { 151.2 Java Solution 2 - One Pass
DoublyLinkedListNode p = head;
DoublyLinkedListNode newHead = head; Use fast and slow pointers. The fast pointer is n steps ahead of the slow pointer. When the fast reaches the end,
the slow pointer points at the previous element of the target element.
while(p!=null){
DoublyLinkedListNode t = p.next; public ListNode removeNthFromEnd(ListNode head, int n) {
p.next = p.prev; if(head == null)
p.prev = t; return null;

289 | 568 Program Creek 290 | 568 291 | 568


151 Remove Nth Node From End of List 152 Palindrome Linked List

ListNode fast = head;


ListNode slow = head; while(fast.next!=null && fast.next.next!=null){
fast = fast.next.next;
for(int i=0; i<n; i++){ slow = slow.next;
fast = fast.next; }
} 152 Palindrome Linked List
ListNode secondHead = slow.next;
//if remove the first node slow.next = null;
if(fast == null){ Given a singly linked list, determine if it is a palindrome.
head = head.next; //reverse second part of the list
return head; ListNode p1 = secondHead;
} 152.1 Java Solution 1 - Creat a new reversed list ListNode p2 = p1.next;

while(fast.next != null){ We can create a new list in reversed order and then compare each node. The time and space are O(n). while(p1!=null && p2!=null){
fast = fast.next; ListNode temp = p2.next;
public boolean isPalindrome(ListNode head) {
slow = slow.next; p2.next = p1;
if(head == null)
} p1 = p2;
return true;
p2 = temp;
slow.next = slow.next.next; }
ListNode p = head;
ListNode prev = new ListNode(head.val);
return head; secondHead.next = null;
}
while(p.next != null){
//compare two sublists now
ListNode temp = new ListNode(p.next.val);
ListNode p = (p2==null?p1:p2);
temp.next = prev;
ListNode q = head;
prev = temp;
while(p!=null){
p = p.next;
if(p.val != q.val)
}
return false;

ListNode p1 = head;
p = p.next;
ListNode p2 = prev;
q = q.next;

while(p1!=null){
}
if(p1.val != p2.val)
return false;
return true;
}
p1 = p1.next;
p2 = p2.next;
}

152.3 Java Solution 3 - Recursive


return true;
}
public class Solution {
ListNode left;

152.2 Java Solution 2 - Break and reverse second half public boolean isPalindrome(ListNode head) {
left = head;
We can use a fast and slow pointer to get the center of the list, then reverse the second list and compare two
sublists. The time is O(n) and space is O(1). boolean result = helper(head);
return result;
public boolean isPalindrome(ListNode head) { }

if(head == null || head.next==null) public boolean helper(ListNode right){


return true;
//stop recursion
//find list center if (right == null)
ListNode fast = head; return true;
ListNode slow = head;

Program Creek 292 | 568 293 | 568 Program Creek 294 | 568
152 Palindrome Linked List

//if sub-list is not palindrome, return false


boolean x = helper(right.next);
if (!x)
return false;

//current left and right 153 Delete Node in a Linked List 154 Reverse Nodes in kGroup
boolean y = (left.val == right.val);

//move left to next Write a function to delete a node (except the tail) in a singly linked list, given only access to that node. Given a linked list, reverse the nodes of a linked list k at a time and return its modified list. If the number of
left = left.next; Supposed the linked list is 1 ->2 ->3 ->4 and you are given the third node with value 3, the linked list should 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
become 1 ->2 ->4 after calling your function. the nodes, only nodes itself may be changed.
return y; For example,
}
} 153.1 Java Solution Given this linked list: 1->2->3->4->5
For k = 2, you should return: 2->1->4->3->5
Time is O(n) and space is O(n). For k = 3, you should return: 3->2->1->4->5
public void deleteNode(ListNode node) {
node.val = node.next.val;
node.next = node.next.next;
} 154.1 Java Solution

public ListNode reverseKGroup(ListNode head, int k) {


if(head==null||k==1)
return head;

ListNode fake = new ListNode(0);


fake.next = head;
ListNode prev = fake;
int i=0;

ListNode p = head;
while(p!=null){
i++;
if(i%k==0){
prev = reverse(prev, p.next);
p = prev.next;
}else{
p = p.next;
}
}

return fake.next;
}

public ListNode reverse(ListNode prev, ListNode next){


ListNode last = prev.next;
ListNode curr = last.next;

while(curr != next){
last.next = curr.next;
curr.next = prev.next;
prev.next = curr;
curr = last.next;
}

return last;

Program Creek 295 | 568 296 | 568 297 | 568


154 Reverse Nodes in kGroup 154 Reverse Nodes in kGroup

} }

We can write the reverse method differently like the following. I personally it is more understandable.

155 Plus One Linked List


Given a non-negative number represented as a singly linked list of digits, plus one to the number.
The digits are stored such that the most significant digit is at the head of the list.
Example:

Input:
1->2->3

Output:
1->2->4

155.1 Java Solution

public ListNode plusOne(ListNode head) {


ListNode h2 = reverse(head);

ListNode p=h2;

while(p!=null){
if(p.val+1<=9){
p.val=p.val+1;
break;
}else{
p.val=0;
if(p.next==null){
p.next = new ListNode(1);
break;
}
p=p.next;
}
}

private ListNode reverse(ListNode prev, ListNode next){ return reverse(h2);


ListNode p1 = prev.next; }
ListNode p2 = p1.next;
public ListNode reverse(ListNode head){
while(p2 != next){ if(head==null||head.next==null)
ListNode t = p2.next; return head;
p2.next = p1;
p1 = p2; ListNode p1=head;
p2 = t; ListNode p2=p1.next;
} while(p2!=null){
ListNode t = p2.next;
ListNode rNode = prev.next; p2.next=p1;
p1=p2;
prev.next.next = next; p2=t;
prev.next = p1; }

return rNode;

Program Creek 298 | 568 Program Creek 299 | 568 300 | 568
155 Plus One Linked List

head.next=null;

return p1;
}

156 Binary Tree Preorder Traversal 157 Binary Tree Inorder Traversal
Preorder binary tree traversal is a classic interview problem. The key to solve this problem is using a stack to There are 3 solutions for solving this problem.
store left and right children, and push right child first so that it is processed after the left child.

157.1 Java Solution 1 - Iterative


156.1 Java Solution
The key to solve inorder traversal of binary tree includes the following:

public class TreeNode { • The order of "inorder" is: left child ->parent ->right child
int val; • Use a stack to track nodes
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; } public List<Integer> inorderTraversal(TreeNode root) {
} ArrayList<Integer> result = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
public class Solution {
public ArrayList<Integer> preorderTraversal(TreeNode root) { TreeNode p = root;
ArrayList<Integer> returnList = new ArrayList<Integer>(); while(p!=null){
stack.push(p);
if(root == null) p=p.left;
return returnList; }

Stack<TreeNode> stack = new Stack<TreeNode>(); while(!stack.isEmpty()){


stack.push(root); TreeNode t = stack.pop();
result.add(t.val);
while(!stack.empty()){
TreeNode n = stack.pop(); t = t.right;
returnList.add(n.val); while(t!=null){
stack.push(t);
if(n.right != null){ t = t.left;
stack.push(n.right); }
} }
if(n.left != null){
stack.push(n.left); return result;
} }

}
return returnList;
} 157.2 Java Solution 2 - Recursive
}
The recursive solution is trivial.

public class Solution {


List<Integer> result = new ArrayList<Integer>();

public List<Integer> inorderTraversal(TreeNode root) {


if(root !=null){
helper(root);
}

return result;
}

Program Creek 301 | 568 302 | 568 303 | 568


157 Binary Tree Inorder Traversal 158 Binary Tree Postorder Traversal

TreeNode curr = stack.peek();


public void helper(TreeNode p){
if(p.left!=null) // go down the tree.
helper(p.left); //check if current node is leaf, if so, process it and pop stack,
//otherwise, keep going down
result.add(p.val); 158 Binary Tree Postorder Traversal if(prev == null || prev.left == curr || prev.right == curr){
//prev == null is the situation for the root node
if(p.right!=null) if(curr.left != null){
helper(p.right); Among preoder, inorder and postorder binary tree traversal problems, postorder traversal is the most complicated stack.push(curr.left);
} one. }else if(curr.right != null){
} stack.push(curr.right);
}else{
stack.pop();
lst.add(curr.val);
157.3 Java Solution 3 - Simple }

The following solution is simple, but it changes the tree structure, i.e., remove pointers to left and right children. //go up the tree from left node
//need to check if there is a right child
public List<Integer> inorderTraversal(TreeNode root) { //if yes, push it to stack
List<Integer> result = new ArrayList<Integer>(); //otherwise, process parent and pop stack
if(root==null) }else if(curr.left == prev){
return result; if(curr.right != null){
Stack<TreeNode> stack = new Stack<TreeNode>(); stack.push(curr.right);
158.1 Java Solution 1
stack.push(root); }else{
stack.pop();
The key to to iterative postorder traversal is the following:
while(!stack.isEmpty()){ lst.add(curr.val);
TreeNode top = stack.peek(); • The order of "Postorder" is: left child ->right child ->parent node. }
if(top.left!=null){
stack.push(top.left); • Find the relation between the previously visited node and the current node //go up the tree from right node
top.left=null; • Use a stack to track nodes //after coming back from right node, process parent node and pop stack.
}else{ }else if(curr.right == prev){
result.add(top.val); As we go down the tree to the lft, check the previously visited node. If the current node is the left or right child stack.pop();
stack.pop(); of the previous node, then keep going down the tree, and add left/right node to stack when applicable. When lst.add(curr.val);
if(top.right!=null){ there is no children for current node, i.e., the current node is a leaf, pop it from the stack. Then the previous node }
stack.push(top.right); become to be under the current node for next loop. You can using an example to walk through the code.
} prev = curr;
} //Definition for binary tree }
} public class TreeNode {
int val; return lst;
return result; TreeNode left; }
} TreeNode right; }
TreeNode(int x) { val = x; }
}

158.2 Java Solution 2 - Simple!


public class Solution {
public ArrayList<Integer> postorderTraversal(TreeNode root) { This solution is simple, but note that the tree’s structure gets changed since children are set to null.

ArrayList<Integer> lst = new ArrayList<Integer>(); public List<Integer> postorderTraversal(TreeNode root) {


List<Integer> res = new ArrayList<Integer>();
if(root == null)
return lst; if(root==null) {
return res;
Stack<TreeNode> stack = new Stack<TreeNode>(); }
stack.push(root);
Stack<TreeNode> stack = new Stack<TreeNode>();
TreeNode prev = null; stack.push(root);
while(!stack.empty()){

Program Creek 304 | 568 305 | 568 Program Creek 306 | 568
158 Binary Tree Postorder Traversal 159 Binary Tree Level Order Traversal

while(!stack.isEmpty()) { 159.2 Java Solution 2


TreeNode temp = stack.peek();
if(temp.left==null && temp.right==null) { We can also improve Solution 1 by use a queue of integer to track the level instead of track another level of nodes.
TreeNode pop = stack.pop();
res.add(pop.val); public List<List<Integer>> levelOrder(TreeNode root) {
} 159 Binary Tree Level Order Traversal List<List<Integer>> result = new ArrayList<>();
else {
if(temp.right!=null) { if(root==null){
stack.push(temp.right); Given a binary tree, return the level order traversal of its nodes’ values. (ie, from left to right, level by level). return result;
temp.right = null; For example: Given binary tree 3,9,20,#,#,15,7, }
}
3 LinkedList<TreeNode> nodeQueue = new LinkedList<>();
if(temp.left!=null) { / \ LinkedList<Integer> levelQueue = new LinkedList<>();
stack.push(temp.left); 9 20
temp.left = null; / \ nodeQueue.offer(root);
} 15 7 levelQueue.offer(1);//start from 1
}
} return its level order traversal as [[3], [9,20], [15,7]] while(!nodeQueue.isEmpty()){
TreeNode node = nodeQueue.poll();
return res; int level = levelQueue.poll();
} 159.1 Java Solution 1
List<Integer> l=null;
It is obvious that this problem can be solve by using a queue. However, if we use one queue we can not track if(result.size()<level){
when each level starts. So we use two queues to track the current level and the next level. l = new ArrayList<>();
result.add(l);
public ArrayList<ArrayList<Integer>> levelOrder(TreeNode root) { }else{
ArrayList<ArrayList<Integer>> al = new ArrayList<ArrayList<Integer>>(); l = result.get(level-1);
ArrayList<Integer> nodeValues = new ArrayList<Integer>(); }
if(root == null)
return al; l.add(node.val);

LinkedList<TreeNode> current = new LinkedList<TreeNode>(); if(node.left!=null){


LinkedList<TreeNode> next = new LinkedList<TreeNode>(); nodeQueue.offer(node.left);
current.add(root); levelQueue.offer(level+1);
}
while(!current.isEmpty()){
TreeNode node = current.remove(); if(node.right!=null){
nodeQueue.offer(node.right);
if(node.left != null) levelQueue.offer(level+1);
next.add(node.left); }
if(node.right != null) }
next.add(node.right);
return result;
nodeValues.add(node.val); }
if(current.isEmpty()){
current = next;
next = new LinkedList<TreeNode>();
al.add(nodeValues);
nodeValues = new ArrayList();
}

}
return al;
}

Program Creek 307 | 568 308 | 568 Program Creek 309 | 568
160 Binary Tree Level Order Traversal II

ArrayList<ArrayList<Integer>> reversedResult = new ArrayList<ArrayList<Integer>>();


for(int i=result.size()-1; i>=0; i--){
reversedResult.add(result.get(i));
}

160 Binary Tree Level Order Traversal II return reversedResult; 161 Binary Tree Vertical Order Traversal
}

Given a binary tree, return the bottom-up level order traversal of its nodes’ values. Given a binary tree, return the vertical order traversal of its nodes’ values. (ie, from top to bottom, column by
For example, given binary tree 3,9,20,#,#,15,7, column).

3
/ \ 161.1 Java Solution
9 20
/ \ For each node, its left child’s degree is -1 and is right child’s degree is +1. We can do a level order traversal and
15 7
save the degree information.

return its level order traversal as [[15,7], [9,20],[3]] public List<List<Integer>> verticalOrder(TreeNode root) {
TreeMap<Integer, ArrayList<Integer>> map = new TreeMap<>();
helper(root, map);
160.1 Java Solution List<List<Integer>> result = new ArrayList<>();
result.addAll(map.values());
return result;
public List<ArrayList<Integer>> levelOrderBottom(TreeNode root) { }
ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();
private void helper(TreeNode t, TreeMap<Integer, ArrayList<Integer>> map) {
if(root == null){ if (t == null) {
return result; return;
} }

LinkedList<TreeNode> current = new LinkedList<TreeNode>(); LinkedList<TreeNode> q1 = new LinkedList<>();


LinkedList<TreeNode> next = new LinkedList<TreeNode>(); LinkedList<Integer> q2 = new LinkedList<>();
current.offer(root); q1.offer(t);
q2.offer(0);
ArrayList<Integer> numberList = new ArrayList<Integer>();
while (!q1.isEmpty()) {
// need to track when each level starts TreeNode node = q1.poll();
while(!current.isEmpty()){ int order = q2.poll();
TreeNode head = current.poll();
//add to map
numberList.add(head.val); ArrayList<Integer> list = map.get(order);
if (list == null) {
if(head.left != null){ list = new ArrayList<>();
next.offer(head.left); map.put(order, list);
} }
if(head.right!= null){ list.add(node.val);
next.offer(head.right);
} if (node.left != null) {
q1.offer(node.left);
if(current.isEmpty()){ q2.offer(order - 1);
current = next; }
next = new LinkedList<TreeNode>();
result.add(numberList); if (node.right != null) {
numberList = new ArrayList<Integer>(); q1.offer(node.right);
} q2.offer(order + 1);
} }
}
//return Collections.reverse(result); }

310 | 568 Program Creek 311 | 568 312 | 568


161 Binary Tree Vertical Order Traversal

Time complexity is O(n*log(n)) and space complexity is O(n). n is the number of nodes on the tree.

162 Invert Binary Tree 163 Kth Smallest Element in a BST


Given a binary search tree, write a function kthSmallest to find the kth smallest element in it. (1 ≤ k ≤ BST’s total
162.1 Java Solution 1 - Recursive
elements)

public TreeNode invertTree(TreeNode root) {


helper(root); 163.1 Java Solution 1 - Inorder Traversal
return root;
} We can inorder traverse the tree and get the kth smallest element. Time is O(n).

public void helper(TreeNode n){ public int kthSmallest(TreeNode root, int k) {


if(n==null){ Stack<TreeNode> stack = new Stack<TreeNode>();
return;
} TreeNode p = root;
int result = 0;
TreeNode t = n.left;
n.left = n.right; while(!stack.isEmpty() || p!=null){
n.right = t; if(p!=null){
stack.push(p);
helper(n.left); p = p.left;
helper(n.right); }else{
} TreeNode t = stack.pop();
k--;
if(k==0)
result = t.val;
p = t.right;
162.2 Java Solution 2 - Iterative
}
}
public TreeNode invertTree(TreeNode root) {
LinkedList<TreeNode> queue = new LinkedList<TreeNode>(); return result;
}
if(root!=null){
queue.add(root); Similarly, we can also write the inorder traversal as the following:
}
public int kthSmallest(TreeNode root, int k) {
while(!queue.isEmpty()){ Stack<TreeNode> stack = new Stack<TreeNode>();
TreeNode p = queue.poll(); TreeNode p = root;
if(p.left!=null) while(p!=null){
queue.add(p.left); stack.push(p);
if(p.right!=null) p=p.left;
queue.add(p.right); }
int i=0;
TreeNode temp = p.left; while(!stack.isEmpty()){
p.left = p.right; TreeNode t = stack.pop();
p.right = temp; i++;
}
if(i==k)
return root; return t.val;
}
TreeNode r = t.right;
while(r!=null){
stack.push(r);

Program Creek 313 | 568 314 | 568 315 | 568


163 Kth Smallest Element in a BST 164 Binary Tree Longest Consecutive Sequence

r=r.left; }
}
return max;
} }

return -1; 164 Binary Tree Longest Consecutive Sequence


}
164.2 Java Solution 2 - DFS
Given a binary tree, find the length of the longest consecutive sequence path.
The path refers to any sequence of nodes from some starting node to any node in the tree along the parent-child
163.2 Java Solution 2 - Extra Data Structure connections. The longest consecutive path need to be from parent to child (cannot be the reverse). class Solution {
int max;
We can let each node track the order, i.e., the number of elements that are less than itself. Time is O(log(n)).
164.1 Java Solution 1 - BFS public int longestConsecutive(TreeNode root) {
helper(root);
return max;
public int longestConsecutive(TreeNode root) { }
if(root==null)
return 0; private int helper(TreeNode t){
if(t==null){
LinkedList<TreeNode> nodeQueue = new LinkedList<TreeNode>(); return 0;
LinkedList<Integer> sizeQueue = new LinkedList<Integer>(); }

nodeQueue.offer(root); int leftMax = helper(t.left);


sizeQueue.offer(1); int rightMax = helper(t.right);
int max=1;
int leftTotal = 0;
while(!nodeQueue.isEmpty()){ if(t.left == null){
TreeNode head = nodeQueue.poll(); leftTotal = 1;
int size = sizeQueue.poll(); }else if(t.val+1 == t.left.val){
leftTotal = leftMax+1;
if(head.left!=null){ }else{
int leftSize=size; leftTotal = 1;
if(head.val==head.left.val-1){ }
leftSize++;
max = Math.max(max, leftSize); int rightTotal = 0;
}else{ if(t.right == null){
leftSize=1; rightTotal = 1;
} }else if(t.val+1 == t.right.val){
rightTotal = rightMax+1;
nodeQueue.offer(head.left); }else{
sizeQueue.offer(leftSize); rightTotal = 1;
} }

if(head.right!=null){ max = Math.max(max, leftTotal);


int rightSize=size; max = Math.max(max, rightTotal);
if(head.val==head.right.val-1){
rightSize++; int longer = Math.max(leftTotal, rightTotal);
max = Math.max(max, rightSize);
}else{ return longer;
rightSize=1; }
} }

nodeQueue.offer(head.right);
sizeQueue.offer(rightSize);
}

Program Creek 316 | 568 317 | 568 Program Creek 318 | 568
165 Validate Binary Search Tree

return true;
}

165 Validate Binary Search Tree 166 Flatten Binary Tree to Linked List
165.2 Java Solution 2 - Iterative
Given a binary tree, determine if it is a valid binary search tree (BST). Given a binary tree, flatten it to a linked list in-place.
Assume a BST is defined as follows: For example, Given
public class Solution {
• The left subtree of a node contains only nodes with keys less than the node’s key. public boolean isValidBST(TreeNode root) { 1
if(root == null) / \
• The right subtree of a node contains only nodes with keys greater than the node’s key. 2 5
return true;
• Both the left and right subtrees must also be binary search trees. / \ \
LinkedList<BNode> queue = new LinkedList<BNode>(); 3 4 6
queue.add(new BNode(root, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
165.1 Java Solution 1 - Recursive while(!queue.isEmpty()){ The flattened tree should look like:
BNode b = queue.poll();
All values on the left sub tree must be less than parent and parent’s parent, and all values on the right sub tree if(b.n.val <= b.left || b.n.val >=b.right){ 1
must be greater than parent and parent’s parent. So we just check the boundaries for each node. return false; \
} 2
public boolean isValidBST(TreeNode root) { if(b.n.left!=null){ \
return isValidBST(root, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY); queue.offer(new BNode(b.n.left, b.left, b.n.val)); 3
} } \
if(b.n.right!=null){ 4
public boolean isValidBST(TreeNode p, double min, double max){ queue.offer(new BNode(b.n.right, b.n.val, b.right)); \
if(p==null) } 5
return true; } \
return true; 6
if(p.val <= min || p.val >= max) }
return false; }
//define a BNode class with TreeNode and it’s boundaries
return isValidBST(p.left, min, p.val) && isValidBST(p.right, p.val, max); class BNode{ 166.1 Java Solution
} TreeNode n;
double left; Go down the tree to the left, when the right child is not null, push the right child to the stack.
This solution also goes to the left subtree first. If the violation occurs close to the root but on the right subtree, double right;
the method still cost time O(n) and space O(h). public BNode(TreeNode n, double left, double right){ /**

The following solution can handle violations close to root node faster. this.n = n; * Definition for binary tree
this.left = left; * public class TreeNode {
public boolean isValidBST(TreeNode root) { this.right = right; * int val;
return helper(root, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY); } * TreeNode left;
} } * TreeNode right;
* TreeNode(int x) { val = x; }
public boolean helper(TreeNode root, double min, double max){ Time and space are both O(n). * }
if(root==null){ */
return true; public class Solution {
public void flatten(TreeNode root) {
} 165.3 Java Solution 3 - In-order traversal Stack<TreeNode> stack = new Stack<TreeNode>();
if(root.val<=min||root.val>=max){ TreeNode p = root;
Since inorder traversal of BST is ascending, so we can check the sequence. Time is O(n) and space is O(h). h is
return false;
the height of the stack which is the tree’s height. while(p != null || !stack.empty()){
}

boolean isLeftBST = helper(root.left, min, root.val); if(p.right != null){


boolean isRightBST = helper(root.right, root.val, max); stack.push(p.right);
}
if(!isLeftBST||!isRightBST){
return false; if(p.left != null){

319 | 568 Program Creek 320 | 568 321 | 568


166 Flatten Binary Tree to Linked List 167 Path Sum

p.right = p.left; nodes.add(curr.left);


p.left = null; values.add(sumValue+curr.left.val);
}else if(!stack.empty()){ }
TreeNode temp = stack.pop();
p.right=temp; if(curr.right != null){
} 167 Path Sum nodes.add(curr.right);
values.add(sumValue+curr.right.val);
p = p.right; }
} Given a binary tree and a sum, determine if the tree has a root-to-leaf path such that adding up all the values }
} along the path equals the given sum.
} For example: Given the below binary tree and sum = 22, return false;
}
5 }
/ \
4 8
/ / \
11 13 4 167.2 Java Solution 2 - Recursion
/ \ \
7 2 1
public boolean hasPathSum(TreeNode root, int sum) {
return true, as there exist a root-to-leaf path 5->4->11->2 which sum is 22. if (root == null)
return false;
if (root.val == sum && (root.left == null && root.right == null))
167.1 Java Solution 1 - Using Queue return true;

Add all node to a queue and store sum value of each node to another queue. When it is a leaf node, check the return hasPathSum(root.left, sum - root.val)
stored sum value. || hasPathSum(root.right, sum - root.val);
For the tree above, the queue would be: 5 - 4 - 8 - 11 - 13 - 4 - 7 - 2 - 1. It will check node 13, 7, 2 and 1. This is }

a typical breadth first search(BFS) problem.


Thanks to nebulaliang, this solution is wonderful!
/**
* Definition for binary tree
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public boolean hasPathSum(TreeNode root, int sum) {
if(root == null) return false;

LinkedList<TreeNode> nodes = new LinkedList<TreeNode>();


LinkedList<Integer> values = new LinkedList<Integer>();

nodes.add(root);
values.add(root.val);

while(!nodes.isEmpty()){
TreeNode curr = nodes.poll();
int sumValue = values.poll();

if(curr.left == null && curr.right == null && sumValue==sum){


return true;
}

if(curr.left != null){

Program Creek 322 | 568 323 | 568 Program Creek 324 | 568
168 Path Sum II

dfs(t.left, sum-t.left.val, result, l);


l.remove(l.size()-1);
}

//search path of right node


168 Path Sum II if(t.right!=null){ 169 Construct Binary Tree from Inorder and
l.add(t.right.val);

Given a binary tree and a sum, find all root-to-leaf paths where each path’s sum equals the given sum.
dfs(t.right, sum-t.right.val, result, l); Postorder Traversal
l.remove(l.size()-1);
For example, given the below binary tree and sum = 22, }
} Given inorder and postorder traversal of a tree, construct the binary tree.
5
/ \
4 8
169.1 Analysis
/ / \
11 13 4
This problem can be illustrated by using a simple example.
/ \ / \
7 2 5 1 in-order: 4 2 5 (1) 6 7 3 8
post-order: 4 5 2 6 7 8 3 (1)
the method returns the following:
From the post-order array, we know that last element is the root. We can find the root in in-order array. Then
[
we can identify the left and right sub-trees of the root from in-order array.
[5,4,11,2],
[5,8,4,5]
Using the length of left sub-tree, we can identify left and right sub-trees in post-order array. Recursively, we
] can build up the tree.

168.1 Analysis
This problem can be converted to be a typical depth-first search problem. A recursive depth-first search algorithm
usually requires a recursive method call, a reference to the final result, a temporary result, etc.

168.2 Java Solution

public List<ArrayList<Integer>> pathSum(TreeNode root, int sum) {


ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();
if(root == null)
169.2 Java Solution
return result;
public TreeNode buildTree(int[] inorder, int[] postorder) {
ArrayList<Integer> l = new ArrayList<Integer>(); int inStart = 0;
l.add(root.val); int inEnd = inorder.length - 1;
dfs(root, sum-root.val, result, l); int postStart = 0;
return result; int postEnd = postorder.length - 1;
}
return buildTree(inorder, inStart, inEnd, postorder, postStart, postEnd);
public void dfs(TreeNode t, int sum, ArrayList<ArrayList<Integer>> result, ArrayList<Integer> l){ }
if(t.left==null && t.right==null && sum==0){
ArrayList<Integer> temp = new ArrayList<Integer>(); public TreeNode buildTree(int[] inorder, int inStart, int inEnd,
temp.addAll(l); int[] postorder, int postStart, int postEnd) {
result.add(temp); if (inStart > inEnd || postStart > postEnd)
} return null;

//search path of left node int rootValue = postorder[postEnd];


if(t.left != null){ TreeNode root = new TreeNode(rootValue);
l.add(t.left.val);

325 | 568 Program Creek 326 | 568 327 | 568


169 Construct Binary Tree from Inorder and Postorder Traversal 170 Construct Binary Tree from Preorder and Inorder Traversal

int k = 0;
for (int i = 0; i < inorder.length; i++) { //find parent element index from inorder
if (inorder[i] == rootValue) { int k=0;
k = i; for(int i=0; i<inorder.length; i++){
break; if(val == inorder[i]){
} 170 Construct Binary Tree from Preorder and k=i;
} break;
Inorder Traversal }
root.left = buildTree(inorder, inStart, k - 1, postorder, postStart, }
postStart + k - (inStart + 1));
// Becuase k is not the length, it it need to -(inStart+1) to get the length Given preorder and inorder traversal of a tree, construct the binary tree. p.left = construct(preorder, preStart+1, preStart+(k-inStart), inorder, inStart, k-1);
root.right = buildTree(inorder, k + 1, inEnd, postorder, postStart + k- inStart, postEnd - 1); p.right= construct(preorder, preStart+(k-inStart)+1, preEnd, inorder, k+1 , inEnd);
// postStart+k-inStart = postStart+k-(inStart+1) +1
170.1 Analysis return p;
return root; }
} Consider the following example:

in-order: 4 2 5 (1) 6 7 3 8
pre-order: (1) 2 4 5 3 7 6 8

From the pre-order array, we know that first element is the root. We can find the root in in-order array. Then
we can identify the left and right sub-trees of the root from in-order array.
Using the length of left sub-tree, we can identify left and right sub-trees in pre-order array. Recursively, we can
build up the tree.

170.2 Java Solution

public TreeNode buildTree(int[] preorder, int[] inorder) {


int preStart = 0;
int preEnd = preorder.length-1;
int inStart = 0;
int inEnd = inorder.length-1;

return construct(preorder, preStart, preEnd, inorder, inStart, inEnd);


}

public TreeNode construct(int[] preorder, int preStart, int preEnd, int[] inorder, int inStart, int
inEnd){
if(preStart>preEnd||inStart>inEnd){
return null;
}

int val = preorder[preStart];


TreeNode p = new TreeNode(val);

Program Creek 328 | 568 329 | 568 Program Creek 330 | 568
172 Convert Sorted List to Binary Search Tree

int len = 0;
ListNode p = head;

while (p != null) {
len++;
171 Convert Sorted Array to Binary Search Tree 172 Convert Sorted List to Binary Search Tree p = p.next;
}
return len;
Given an array where elements are sorted in ascending order, convert it to a height balanced BST. Given a singly linked list where elements are sorted in ascending order, convert it to a height balanced BST. }

// build tree bottom-up


171.1 Java Solution 172.1 Thoughts public TreeNode sortedListToBST(int start, int end) {
if (start > end)
A typical DFS problem using recursion. If you are given an array, the problem is quite straightforward. But things get a little more complicated when you return null;
have a singly linked list instead of an array. Now you no longer have random access to an element in O(1) time.
// Definition for binary tree
Therefore, you need to create nodes bottom-up, and assign them to its parents. The bottom-up approach enables // mid
class TreeNode {
us to access the list in its order at the same time as creating nodes. int mid = (start + end) / 2;
int val;
TreeNode left;
TreeNode left = sortedListToBST(start, mid - 1);
TreeNode right;
172.2 Java Solution TreeNode root = new TreeNode(h.val);
h = h.next;
TreeNode(int x) {
TreeNode right = sortedListToBST(mid + 1, end);
val = x; // Definition for singly-linked list.
} class ListNode { root.left = left;
} int val; root.right = right;
ListNode next;
public class Solution {
return root;
public TreeNode sortedArrayToBST(int[] num) { ListNode(int x) { }
if (num.length == 0) val = x; }
return null; next = null;
}
return sortedArrayToBST(num, 0, num.length - 1); }
}
// Definition for binary tree
public TreeNode sortedArrayToBST(int[] num, int start, int end) { class TreeNode {
if (start > end) int val;
return null; TreeNode left;
TreeNode right;
int mid = (start + end) / 2;
TreeNode root = new TreeNode(num[mid]); TreeNode(int x) {
root.left = sortedArrayToBST(num, start, mid - 1); val = x;
root.right = sortedArrayToBST(num, mid + 1, end); }
}
return root;
} public class Solution {
} static ListNode h;

public TreeNode sortedListToBST(ListNode head) {


if (head == null)
return null;

h = head;
int len = getLength(head);
return sortedListToBST(0, len - 1);
}

// get list length


public int getLength(ListNode head) {

331 | 568 332 | 568 Program Creek 333 | 568


173 Minimum Depth of Binary Tree

}
}

return 0;
}
173 Minimum Depth of Binary Tree } 174 Binary Tree Maximum Path Sum
Given a binary tree, find its minimum depth. Given a binary tree, find the maximum path sum. The path may start and end at any node in the tree. For
The minimum depth is the number of nodes along the shortest path from the root node down to the nearest example, given the below binary tree
leaf node.
1
/ \
173.1 Thoughts 2 3

LinkedList is a queue in Java. The add() and remove() methods are used to manipulate the queue. the result is 6.

173.2 Java Solution 174.1 Analysis


1) Recursively solve this problem 2) Get largest left sum and right sum 2) Compare to the stored maximum
/**
* Definition for binary tree
* public class TreeNode { 174.2 Java Solution
* int val;
* TreeNode left; We can also use an array to store value for recursive methods.
* TreeNode right;
* TreeNode(int x) { val = x; } public int maxPathSum(TreeNode root) {
* } int max[] = new int[1];
*/ max[0] = Integer.MIN_VALUE;
public class Solution { calculateSum(root, max);
public int minDepth(TreeNode root) { return max[0];
if(root == null){ }
return 0;
} public int calculateSum(TreeNode root, int[] max) {
if (root == null)
LinkedList<TreeNode> nodes = new LinkedList<TreeNode>(); return 0;
LinkedList<Integer> counts = new LinkedList<Integer>();
int left = calculateSum(root.left, max);
nodes.add(root); int right = calculateSum(root.right, max);
counts.add(1);
int current = Math.max(root.val, Math.max(root.val + left, root.val + right));
while(!nodes.isEmpty()){
TreeNode curr = nodes.remove(); max[0] = Math.max(max[0], Math.max(current, left + root.val + right));
int count = counts.remove();
return current;
if(curr.left == null && curr.right == null){ }
return count;
}

if(curr.left != null){
nodes.add(curr.left);
counts.add(count+1);
}

if(curr.right != null){
nodes.add(curr.right);
counts.add(count+1);

334 | 568 Program Creek 335 | 568 336 | 568


175 Balanced Binary Tree

}
}

175 Balanced Binary Tree 176 Symmetric Tree


Given a binary tree, determine if it is height-balanced. 176.1 Problem
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. Given a binary tree, check whether it is a mirror of itself (ie, symmetric around its center).
For example, this binary tree is symmetric:

175.1 Analysis 1
/ \
This is a typical tree problem that can be solve by using recursion. 2 2
/ \ / \
3 4 4 3
175.2 Java Solution
But the following is not:
// Definition for binary tree 1
class TreeNode { / \
int val; 2 2
TreeNode left; \ \
TreeNode right; 3 3

TreeNode(int x) {
val = x;
} 176.2 Java Solution - Recursion
}
This problem can be solve by using a simple recursion. The key is finding the conditions that return false, such
public class Solution { as value is not equal, only one node(left or right) has value.
public boolean isBalanced(TreeNode root) {
if (root == null) public boolean isSymmetric(TreeNode root) {
return true; if (root == null)
return true;
if (getHeight(root) == -1) return isSymmetric(root.left, root.right);
return false; }

return true; public boolean isSymmetric(TreeNode l, TreeNode r) {


} if (l == null && r == null) {
return true;
public int getHeight(TreeNode root) { } else if (r == null || l == null) {
if (root == null) return false;
return 0; }

int left = getHeight(root.left); if (l.val != r.val)


int right = getHeight(root.right); return false;

if (left == -1 || right == -1) if (!isSymmetric(l.left, r.right))


return -1; return false;
if (!isSymmetric(l.right, r.left))
if (Math.abs(left - right) > 1) { return false;
return -1;
} return true;
}
return Math.max(left, right) + 1;

337 | 568 Program Creek 338 | 568 339 | 568


177 Binary Search Tree Iterator

}
}

public boolean hasNext() {


return !stack.isEmpty();
177 Binary Search Tree Iterator } 178 Binary Tree Right Side View
public int next() {
TreeNode node = stack.pop(); Given a binary tree, imagine yourself standing on the right side of it, return the values of the nodes you can see
177.1 Problem
int result = node.val; ordered from top to bottom. For example, given the following binary tree,
Implement an iterator over a binary search tree (BST). Your iterator will be initialized with the root node of a BST. if (node.right != null) {
node = node.right; 1 <---
Calling next() will return the next smallest number in the BST. Note: next() and hasNext() should run in average / \
while (node != null) {
O(1) time and uses O(h) memory, where h is the height of the tree. 2 3 <---
stack.push(node);
node = node.left; \
} 5 <---
177.2 Java Solution }
return result; You can see [1, 3, 5].
The key to solve this problem is understanding the features of BST. Here is an example BST. }
}
178.1 Analysis
This problem can be solve by using a queue. On each level of the tree, we add the right-most element to the
results.

178.2 Java Solution

public List<Integer> rightSideView(TreeNode root) {


ArrayList<Integer> result = new ArrayList<Integer>();

if(root == null) return result;

LinkedList<TreeNode> queue = new LinkedList<TreeNode>();


queue.add(root);

while(queue.size() > 0){


//get size here
int size = queue.size();
/**
* Definition for binary tree for(int i=0; i<size; i++){
* public class TreeNode { TreeNode top = queue.remove();
* int val;
* TreeNode left; //the first element in the queue (right-most of the tree)
* TreeNode right; if(i==0){
* TreeNode(int x) { val = x; } result.add(top.val);
* } }
*/ //add right first
if(top.right != null){
public class BSTIterator { queue.add(top.right);
Stack<TreeNode> stack; }
//add left
public BSTIterator(TreeNode root) { if(top.left != null){
stack = new Stack<TreeNode>(); queue.add(top.left);
while (root != null) { }
stack.push(root); }
root = root.left; }

340 | 568 Program Creek 341 | 568 342 | 568


178 Binary Tree Right Side View

return result;
}

Similarly, we can also use two queues which makes the code slightly more readable.
179 Lowest Common Ancestor of a Binary Search 180 Lowest Common Ancestor of a Binary Tree
public List<Integer> rightSideView(TreeNode root) {
LinkedList<TreeNode> q1 = new LinkedList<>(); Tree Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree.
LinkedList<Integer> q2 = new LinkedList<>();

ArrayList<Integer> result = new ArrayList<>(); Given a binary search tree (BST), find the lowest common ancestor (LCA) of two given nodes in the BST.
if (root == null) { 180.1 Java Solution 1
return result;
} 179.1 Analysis public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root==null)
q1.offer(root); This problem can be solved by using BST property, i.e., left <parent <right for each node. There are 3 cases to
return null;
q2.offer(1); handle.
int prev = 0;
if(root==p || root==q)
return root;
while (!q1.isEmpty()) { 179.2 Java Solution 1 - Recursive
TreeNode h = q1.poll();
TreeNode l = lowestCommonAncestor(root.left, p, q);
int level = q2.poll();
TreeNode r = lowestCommonAncestor(root.right, p, q);
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (level != prev) { TreeNode m = root;
if(l!=null&&r!=null){
result.add(h.val);
return root;
} if(m.val > p.val && m.val < q.val){
}else if(l==null&&r==null){
return m;
return null;
if (h.right != null) { }else if(m.val>p.val && m.val > q.val){
}else{
q1.offer(h.right); return lowestCommonAncestor(root.left, p, q);
return l==null?r:l;
q2.offer(level + 1); }else if(m.val<p.val && m.val < q.val){
}
} return lowestCommonAncestor(root.right, p, q);
}
}
if (h.left != null) {
q1.offer(h.left); return root; To calculate time complexity, we know that f(n)=2*f(n-1)=2*2*f(n-2)=2ˆ(logn), so time=O(n).
q2.offer(level + 1); }
}
180.2 Java Solution 2
prev = level;
} 179.3 Java Solution 2 - Iterative class Solution {
return result; public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
} public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { CounterNode n = helper(root, p, q);
TreeNode t = root; return n.node;
}
while(t!=null){
if(p.val >t.val && q.val >t.val){ public CounterNode helper(TreeNode root, TreeNode p, TreeNode q){
t = t.right; if(root==null){
}else if (p.val<t.val && q.val<t.val){ return new CounterNode(null, 0);
t = t.left; }
}else{
return t; CounterNode left = helper(root.left, p, q);
} if(left.count==2){
} return left;
}
return null;
} CounterNode right = helper(root.right, p, q);
if(right.count==2){
return right;

Program Creek 343 | 568 344 | 568 345 | 568


180 Lowest Common Ancestor of a Binary Tree 181 Most Frequent Subtree Sum

} Integer left = helper(root.left, map);


if(left==null){
int c=left.count+right.count+(root==p?1:0)+(root==q?1:0); left=0;
}
return new CounterNode(root, c);
181 Most Frequent Subtree Sum Integer right = helper(root.right, map);
} if(right==null){
} right=0;
Given the root of a tree, you are asked to find the most frequent subtree sum. The subtree sum of a node is }
class CounterNode{ defined as the sum of all the node values formed by the subtree rooted at that node (including the node itself).
public int count; So what is the most frequent subtree sum value? If there is a tie, return all the values with the highest frequency int sum = root.val + left + right;
public TreeNode node; in any order. map.put(sum, map.getOrDefault(sum, 0)+1);
Examples 1 Input:
public CounterNode(TreeNode node, int count){ 5 / 2 -3 return sum;
this.count=count; return [2, -3, 4], since all the values happen only once, return all of them in any order. }
this.node=node;
Examples 2 Input:
}
5 / 2 -5
}
return [2], since 2 happens twice, however -5 only occur once.

181.1 Java Solution


We can solve this problem using a typical recursion on the tree, similar to LCA.

public int[] findFrequentTreeSum(TreeNode root) {


HashMap<Integer,Integer> map = new HashMap<>();

helper(root, map);

int maxCount = 0;
for(int i: map.keySet()){
if(map.get(i)>maxCount){
maxCount=map.get(i);
}
}

List<Integer> mf = new ArrayList<>();


for(Map.Entry<Integer, Integer> entry: map.entrySet()){
if(entry.getValue()==maxCount){
mf.add(entry.getKey());
}
}

int[] result = new int[mf.size()];


int k=0;
for(int i: mf){
result[k++]=i;
}

return result;
}

public Integer helper(TreeNode root, HashMap<Integer,Integer> map){


if(root==null){
return null;
}

Program Creek 346 | 568 347 | 568 Program Creek 348 | 568
182 Verify Preorder Serialization of a Binary Tree

&& stack.get(stack.size()-1).equals("#")
&& stack.get(stack.size()-2).equals("#")
&& !stack.get(stack.size()-3).equals("#")){

stack.remove(stack.size()-1);
182 Verify Preorder Serialization of a Binary Tree stack.remove(stack.size()-1); 183 Populating Next Right Pointers in Each Node
stack.remove(stack.size()-1);

One way to serialize a binary tree is to use pre-order traversal. When we encounter a non-null node, we record stack.add("#"); Given the following perfect binary tree,
the node’s value. If it is a null node, we record using a sentinel value such as #. }
1
9 / \
}
/ \ 2 3
3 2 / \ / \
if(stack.size()==1 && stack.get(0).equals("#"))
/ \ / \ 4 5 6 7
return true;
4 1 # 6 else
/ \ / \ / \ return false;
After calling your function, the tree should look like:
# # # # # # }
1 -> NULL
For example, the above binary tree can be serialized to the string "9,3,4,#,#,1,#,#,2,#,6,#,#", where # represents a / \
If only stack operations are allowed, the solution can be written in the following way: 2 -> 3 -> NULL
null node.
/ \ / \
Given a string of comma separated values, verify whether it is a correct preorder traversal serialization of a public boolean isValidSerialization(String preorder) {
4->5->6->7 -> NULL
binary tree. Find an algorithm without reconstructing the tree. String[] arr = preorder.split(",");

Stack<String> stack = new Stack<>();


182.1 Java Solution for(String s: arr){
183.1 Java Solution 1 - Simple
if(stack.isEmpty() || !s.equals("#")){
We can keep trimming the leaves until there is no one to remove. If a sequence is like "4 # #", change it to "#" and stack.push(s);
continue. A stack is a good date structure for this purpose. }else{
public void connect(TreeLinkNode root) {
while(!stack.isEmpty() && stack.peek().equals("#")){
if(root==null)
stack.pop();
return;
if(stack.isEmpty()){
return false;
LinkedList<TreeLinkNode> nodeQueue = new LinkedList<TreeLinkNode>();
}else{
LinkedList<Integer> depthQueue = new LinkedList<Integer>();
stack.pop();
}
if(root!=null){
}
nodeQueue.offer(root);
stack.push("#");
depthQueue.offer(1);
}
}
}
while(!nodeQueue.isEmpty()){
return stack.size()==1 && stack.peek().equals("#");
TreeLinkNode topNode = nodeQueue.poll();
}
int depth = depthQueue.poll();

if(depthQueue.isEmpty()){
topNode.next = null;
}else if(depthQueue.peek()>depth){
topNode.next = null;
}else{
topNode.next = nodeQueue.peek();
public boolean isValidSerialization(String preorder) { }
LinkedList<String> stack = new LinkedList<String>();
String[] arr = preorder.split(","); if(topNode.left!=null){
nodeQueue.offer(topNode.left);
for(int i=0; i<arr.length; i++){ depthQueue.offer(depth+1);
stack.add(arr[i]); }

while(stack.size()>=3 if(topNode.right!=null){

349 | 568 Program Creek 350 | 568 351 | 568


183 Populating Next Right Pointers in Each Node 183 Populating Next Right Pointers in Each Node

nodeQueue.offer(topNode.right);
depthQueue.offer(depth+1); lastCurrent = lastCurrent.next;
} }
}
} //update last head
lastHead = currentHead; 184 Populating Next Right Pointers in Each Node
currentHead = null;
} II
183.2 Java Solution 2
}
This solution is easier to understand. You can use the example tree above to walk through the algorithm. The Follow up for problem "Populating Next Right Pointers in Each Node".
basic idea is have 4 pointers to move towards right on two levels (see comments in the code). What if the given tree could be any binary tree? Would your previous solution still work?

184.1 Analysis
Similar to Populating Next Right Pointers in Each Node, we have 4 pointers at 2 levels of the tree.

public void connect(TreeLinkNode root) {


if(root == null)
return;
184.2 Java Solution

TreeLinkNode lastHead = root;//prevous level’s head public void connect(TreeLinkNode root) {


TreeLinkNode lastCurrent = null;//previous level’s pointer if(root == null)
TreeLinkNode currentHead = null;//currnet level’s head return;
TreeLinkNode current = null;//current level’s pointer
TreeLinkNode lastHead = root;//prevous level’s head
while(lastHead!=null){ TreeLinkNode lastCurrent = null;//previous level’s pointer
lastCurrent = lastHead; TreeLinkNode currentHead = null;//currnet level’s head
TreeLinkNode current = null;//current level’s pointer
while(lastCurrent!=null){
if(currentHead == null){ while(lastHead!=null){
currentHead = lastCurrent.left; lastCurrent = lastHead;
current = lastCurrent.left;
}else{ while(lastCurrent!=null){
current.next = lastCurrent.left; //left child is not null
current = current.next; if(lastCurrent.left!=null) {
} if(currentHead == null){
currentHead = lastCurrent.left;
if(currentHead != null){ current = lastCurrent.left;
current.next = lastCurrent.right; }else{
current = current.next; current.next = lastCurrent.left;
} current = current.next;

Program Creek 352 | 568 Program Creek 353 | 568 354 | 568
184 Populating Next Right Pointers in Each Node II 185 Unique Binary Search Trees

} for (int j = 0; j <= i - 1; j++) {


} count[i] = count[i] + count[j] * count[i - j - 1];
}
//right child is not null }
if(lastCurrent.right!=null){
if(currentHead == null){ 185 Unique Binary Search Trees return count[n];
currentHead = lastCurrent.right; }
current = lastCurrent.right;
}else{ Given n, how many structurally unique BST’s (binary search trees) that store values 1...n? Check out how to get all unique binary search trees.
current.next = lastCurrent.right; For example, Given n = 3, there are a total of 5 unique BST’s.
current = current.next;
} 1 3 3 2 1
} \ / / / \ \
3 2 1 1 3 2
lastCurrent = lastCurrent.next; / / \ \
} 2 1 2 3

//update last head


lastHead = currentHead;
currentHead = null; 185.1 Analysis
}
} Let count[i] be the number of unique binary search trees for i. The number of trees are determined by the number
of subtrees which have different root node. For example,

i=0, count[0]=1 //empty tree

i=1, count[1]=1 //one tree

i=2, count[2]=count[0]*count[1] // 0 is root


+ count[1]*count[0] // 1 is root

i=3, count[3]=count[0]*count[2] // 1 is root


+ count[1]*count[1] // 2 is root
+ count[2]*count[0] // 3 is root

i=4, count[4]=count[0]*count[3] // 1 is root


+ count[1]*count[2] // 2 is root
+ count[2]*count[1] // 3 is root
+ count[3]*count[0] // 4 is root
..
..
..

i=n, count[n] = sum(count[0..k]*count[k+1...n]) 0 <= k < n-1

Use dynamic programming to solve the problem.

185.2 Java Solution

public int numTrees(int n) {


int[] count = new int[n + 1];

count[0] = 1;
count[1] = 1;

for (int i = 2; i <= n; i++) {

Program Creek 355 | 568 356 | 568 Program Creek 357 | 568
186 Unique Binary Search Trees II

186 Unique Binary Search Trees II 187 Sum Root to Leaf Numbers
Given n, generate all structurally unique BST’s (binary search trees) that store values 1...n. Given a binary tree containing digits from 0-9 only, each root-to-leaf path could represent a number. Find the
For example, Given n = 3, your program should return all 5 unique BST’s shown below. total sum of all root-to-leaf numbers.
For example,
1 3 3 2 1
\ / / / \ \ 1
3 2 1 1 3 2 / \
/ / \ \ 2 3
2 1 2 3
The root-to-leaf path 1->2 represents the number 12. The root-to-leaf path 1->3 represents the number 13.
Return the sum = 12 + 13 = 25.

186.1 Analysis
187.1 Java Solution - Recursive
Check out Unique Binary Search Trees I.
This problem can be solved by recursively forming left and right subtrees. The different combinations of left This problem can be solved by a typical DFS approach.
and right subtrees form the set of all unique binary search trees.
public int sumNumbers(TreeNode root) {
int result = 0;
186.2 Java Solution if(root==null)
return result;

public List<TreeNode> generateTrees(int n) { ArrayList<ArrayList<TreeNode>> all = new ArrayList<ArrayList<TreeNode>>();


if(n==0){ ArrayList<TreeNode> l = new ArrayList<TreeNode>();
return new ArrayList<TreeNode>(); l.add(root);
} dfs(root, l, all);

return helper(1, n); for(ArrayList<TreeNode> a: all){


} StringBuilder sb = new StringBuilder();
for(TreeNode n: a){
public List<TreeNode> helper(int m, int n){ sb.append(String.valueOf(n.val));
List<TreeNode> result = new ArrayList<TreeNode>(); }
if(m>n){ int currValue = Integer.valueOf(sb.toString());
result.add(null); result = result + currValue;
return result; }
}
return result;
for(int i=m; i<=n; i++){ }
List<TreeNode> ls = helper(m, i-1);
List<TreeNode> rs = helper(i+1, n); public void dfs(TreeNode n, ArrayList<TreeNode> l, ArrayList<ArrayList<TreeNode>> all){
for(TreeNode l: ls){ if(n.left==null && n.right==null){
for(TreeNode r: rs){ ArrayList<TreeNode> t = new ArrayList<TreeNode>();
TreeNode curr = new TreeNode(i); t.addAll(l);
curr.left=l; all.add(t);
curr.right=r; }
result.add(curr);
} if(n.left!=null){
} l.add(n.left);
} dfs(n.left, l, all);
l.remove(l.size()-1);
return result; }

358 | 568 Program Creek 359 | 568 360 | 568


187 Sum Root to Leaf Numbers 188 Count Complete Tree Nodes

int left = getLeftHeight(root)+1;


if(n.right!=null){ int right = getRightHeight(root)+1;
l.add(n.right);
dfs(n.right, l, all); if(left==right){
l.remove(l.size()-1); return (2<<(left-1))-1;
} 188 Count Complete Tree Nodes }else{
return countNodes(root.left)+countNodes(root.right)+1;
} }
Given a complete binary tree, count the number of nodes. }
Same approach, but simpler coding style. The solution to this problem can be as simple as the following:
public int getLeftHeight(TreeNode n){
public int sumNumbers(TreeNode root) { public int countNodes(TreeNode root) { if(n==null) return 0;
if(root == null) if(root == null){
return 0; return 0; int height=0;
} while(n.left!=null){
return dfs(root, 0, 0); height++;
} return 1 + countNodes(root.left) + countNodes(root.right); n = n.left;
} }
public int dfs(TreeNode node, int num, int sum){ return height;
if(node == null) return sum; The following two solutions are improvements to this solution. The idea is that we can skip some elements to }
reduce time in the average case.
num = num*10 + node.val; public int getRightHeight(TreeNode n){
if(n==null) return 0;
// leaf 188.1 Java Solution 1
if(node.left == null && node.right == null) { int height=0;
sum += num; Steps to solve this problem: 1) get the height of left-most part 2) get the height of right-most part 3) when they while(n.right!=null){
return sum; are equal, the # of nodes = 2ĥ -1 4) when they are not equal, recursively get # of nodes from left&right sub-trees height++;
} n = n.right;
}
// left subtree + right subtree return height;
sum = dfs(node.left, num, sum) + dfs(node.right, num, sum); }
return sum;
} Each time, you will have to do traversals along the left and right edges. At level h, you iterate zero times (no
child). At level h - 1, you iterate once (one child). And so on. So that is 0 + 1 + 2 + ... + h steps just to compute
the left edges, which is h(1 + h)/2 = O(h2̂). The countNodes part has f(n) = 2 * 2 ...* 2 = 2ĥ which is the number
of nodes. Therefore, the time complexity is bounded by O(n) where n is the number of nodes in the tree.

188.2 Java Solution 2

public int countNodes(TreeNode root) {


int h = getHeight(root);
int total = (int)Math.pow(2, h)-1;

//get num missed


int[] miss = new int[1];
helper(root, 0, h, miss);

return total - miss[0];


}

//true continue, false stop


private boolean helper(TreeNode t, int level, int height, int[] miss){
public int countNodes(TreeNode root) { if(t!=null){
if(root==null) level++;
return 0; }else{
return true;

Program Creek 361 | 568 362 | 568 Program Creek 363 | 568
188 Count Complete Tree Nodes 189 Closest Binary Search Tree Value

} }
root = root.right;
if(level >=height){ }else if(target<root.val){
return false;
} double diff = Math.abs(root.val-target);
189 Closest Binary Search Tree Value if(diff<min){
if(level == height-1){ min = Math.min(min, diff);
if(t.right == null){ result = root.val;
miss[0]++; Given a non-empty binary search tree and a target value, find the value in the BST that is closest to the target. }
} root = root.left;
if(t.left == null){ }else{
miss[0]++; 189.1 Java Solution 1 - Recursion return root.val;
} }
Recursively traverse down the root. When target is less than root, go left; when target is greater than root, go }
if(t.left!=null){ right.
return false; return result;
} public class Solution { }
} int goal;
double min = Double.MAX_VALUE;
boolean r = helper(t.right, level, height, miss);
if(r){ public int closestValue(TreeNode root, double target) {
boolean l = helper(t.left, level, height, miss); helper(root, target);
return l; return goal;
} }

return true; public void helper(TreeNode root, double target){


} if(root==null)
return;
private int getHeight(TreeNode root){
TreeNode p = root; if(Math.abs(root.val - target) < min){
int h = 0; min = Math.abs(root.val-target);
while(p!=null){ goal = root.val;
h++; }
p = p.left;
} if(target < root.val){
return h; helper(root.left, target);
} }else{
helper(root.right, target);
}
The sum of total node can also be written as:
}
int total = (2 << (h-1)) - 1; }

Average time complexity is O(n/2), which is half of the number of nodes in the tree.

189.2 Java Solution 2 - Iteration

public int closestValue(TreeNode root, double target) {


double min=Double.MAX_VALUE;
int result = root.val;

while(root!=null){
if(target>root.val){

double diff = Math.abs(root.val-target);


if(diff<min){
min = Math.min(min, diff);
result = root.val;

Program Creek 364 | 568 365 | 568 Program Creek 366 | 568
190 Binary Tree Paths

190.2 Simplified DFS Solution


This depth-first solution can be much simplified like the following:

public List<String> binaryTreePaths(TreeNode root) {


190 Binary Tree Paths 191 Maximum Depth of Binary Tree
String sb = "";
ArrayList<String> result = new ArrayList<String>();
Given a binary tree, return all root-to-leaf paths. Given a binary tree, find its maximum depth.
helper(root, result, sb); The maximum depth is the number of nodes along the longest path from the root node down to the farthest
leaf node.
190.1 Naive DFS Solution return result;
}
A typical depth-first search problem. 191.1 Java Solution
public void helper(TreeNode root, ArrayList<String> result, String s){
public List<String> binaryTreePaths(TreeNode root) { if(root==null){
ArrayList<String> finalResult = new ArrayList<String>(); return; public int maxDepth(TreeNode root) {
} if(root==null)
if(root==null) return 0;
return finalResult; s = s+"->"+root.val;
int leftDepth = maxDepth(root.left);
ArrayList<String> curr = new ArrayList<String>(); if(root.left==null &&root.right==null){ int rightDepth = maxDepth(root.right);
ArrayList<ArrayList<String>> results = new ArrayList<ArrayList<String>>(); result.add(s.substring(2));
return; int bigger = Math.max(leftDepth, rightDepth);
dfs(root, results, curr); }
return bigger+1;
for(ArrayList<String> al : results){ if(root.left!=null){ }
StringBuilder sb = new StringBuilder(); helper(root.left, result, s);
sb.append(al.get(0)); }
for(int i=1; i<al.size();i++){ if(root.right!=null){
sb.append("->"+al.get(i)); helper(root.right, result, s);
} }
}
finalResult.add(sb.toString());
}

return finalResult;
}

public void dfs(TreeNode root, ArrayList<ArrayList<String>> list, ArrayList<String> curr){


curr.add(String.valueOf(root.val));

if(root.left==null && root.right==null){


list.add(curr);
return;
}

if(root.left!=null){
ArrayList<String> temp = new ArrayList<String>(curr);
dfs(root.left, list, temp);
}

if(root.right!=null){
ArrayList<String> temp = new ArrayList<String>(curr);
dfs(root.right, list, temp);
}
}

367 | 568 Program Creek 368 | 568 369 | 568


192 Recover Binary Search Tree 193 Same Tree 194 Serialize and Deserialize Binary Tree
Two elements of a binary search tree (BST) are swapped by mistake. Recover the tree without changing its Two binary trees are considered the same if they have identical structure and nodes have the same value. Design an algorithm to serialize and deserialize a binary tree. There is no restriction on how your serializa-
structure. This problem can be solved by using a simple recursive function. tion/deserialization algorithm should work. You just need to ensure that a binary tree can be serialized to a
string and this string can be deserialized to the original tree structure.
public boolean isSameTree(TreeNode p, TreeNode q) {
192.1 Java Solution if(p==null && q==null){
return true; 194.1 Java Solution 1 - Level Order Traveral
Inorder traveral will return values in an increasing order. So if an element is less than its previous element,the }else if(p==null || q==null){
return false;
previous element is a swapped node.
} // Encodes a tree to a single string.
public class Solution { public String serialize(TreeNode root) {
TreeNode first; if(p.val==q.val){ if(root==null){
TreeNode second; return isSameTree(p.left, q.left) && isSameTree(p.right, q.right); return "";
TreeNode pre; }else{ }
return false;
public void inorder(TreeNode root){ } StringBuilder sb = new StringBuilder();
if(root==null) }
return; LinkedList<TreeNode> queue = new LinkedList<TreeNode>();

inorder(root.left); queue.add(root);
while(!queue.isEmpty()){
if(pre==null){ TreeNode t = queue.poll();
pre=root; if(t!=null){
}else{ sb.append(String.valueOf(t.val) + ",");
if(root.val<pre.val){ queue.add(t.left);
if(first==null){ queue.add(t.right);
first=pre; }else{
} sb.append("#,");
}
second=root; }
}
pre=root; sb.deleteCharAt(sb.length()-1);
} System.out.println(sb.toString());
return sb.toString();
inorder(root.right); }
}
// Decodes your encoded data to tree.
public void recoverTree(TreeNode root) { public TreeNode deserialize(String data) {
if(root==null) if(data==null || data.length()==0)
return; return null;

inorder(root); String[] arr = data.split(",");


if(second!=null && first !=null){ TreeNode root = new TreeNode(Integer.parseInt(arr[0]));
int val = second.val;
second.val = first.val;
first.val = val; LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
} queue.add(root);

} int i=1;
} while(!queue.isEmpty()){
TreeNode t = queue.poll();

370 | 568 371 | 568 372 | 568


194 Serialize and Deserialize Binary Tree 194 Serialize and Deserialize Binary Tree

if(data == null)
if(t==null) return null;
continue;
int[] t = {0};
if(!arr[i].equals("#")){ String[] arr = data.split(",");
t.left = new TreeNode(Integer.parseInt(arr[i])); 195 Inorder Successor in BST
queue.offer(t.left); return helper(arr, t);
}
}else{ Given a binary search tree and a node in it, find the in-order successor of that node in the BST.
t.left = null; public TreeNode helper(String[] arr, int[] t){
// Definition for a binary tree node.
queue.offer(null); if(arr[t[0]].equals("#")){
public class TreeNode {
} return null;
int val;
i++; }
TreeNode left;
TreeNode right;
if(!arr[i].equals("#")){ TreeNode root = new TreeNode(Integer.parseInt(arr[t[0]]));
TreeNode(int x) { val = x; }
t.right = new TreeNode(Integer.parseInt(arr[i]));
}
queue.offer(t.right); t[0]=t[0]+1;
root.left = helper(arr, t);
}else{ t[0]=t[0]+1;
t.right = null; root.right = helper(arr, t);
queue.offer(null); 195.1 Java Solution
} return root;
i++; } The node does not have a pointer pointing to its parent. This is different from Inorder Successor in BST II.
}
public TreeNode inorderSuccessor(TreeNode root, TreeNode p) {
if(root==null)
return root;
return null;
}

TreeNode next = null;


TreeNode c = root;
while(c!=null && c.val!=p.val){
194.2 Java Solution 2 - Preorder Traversal if(c.val > p.val){
next = c;
// Encodes a tree to a single string. c = c.left;
public String serialize(TreeNode root) { }else{
if(root==null) c= c.right;
return null; }
}
Stack<TreeNode> stack = new Stack<TreeNode>();
stack.push(root); if(c==null)
StringBuilder sb = new StringBuilder(); return null;

while(!stack.isEmpty()){ if(c.right==null)
TreeNode h = stack.pop(); return next;
if(h!=null){
sb.append(h.val+","); c = c.right;
stack.push(h.right); while(c.left!=null)
stack.push(h.left); c = c.left;
}else{
sb.append("#,"); return c;
} }
}
When the tree is balanced, time complexity is O(log(n)) and space is O(1). The worst case time complexity is
return sb.toString().substring(0, sb.length()-1); O(n).
}

// Decodes your encoded data to tree.


public TreeNode deserialize(String data) {

Program Creek 373 | 568 Program Creek 374 | 568 375 | 568
196 Inorder Successor in BST II

196 Inorder Successor in BST II 197 Find Leaves of Binary Tree


Given a binary search tree and a node in it, find the in-order successor of that node in the BST. Given a binary tree, collect a tree’s nodes as if you were doing this: Collect and remove all leaves, repeat until the
The successor of a node p is the node with the smallest key greater than p.val. You will have direct access to tree is empty.
the node but not to the root of the tree. Each node will have a reference to its parent node. A node is defined as Example: Given binary tree
the following:
1
// Definition for a Node. / \
class Node { 2 3
public int val; / \
public Node left; 4 5
public Node right;
public Node parent; Returns [4, 5, 3], [2], [1].
};
*/
197.1 Java Solution 1
Naively, we can get the order of each node, store them in a hashmap and then iterate over the hashmap to get the
196.1 Java Solution list.

public List<List<Integer>> findLeaves(TreeNode root) {


public Node inorderSuccessor(Node x) { HashMap<TreeNode, Integer> map=new HashMap<>();
Node result = null; helper(root, map);

//case 1: right child is not null -> go down to get the next int min = Integer.MAX_VALUE;
Node p = x.right; int max = Integer.MIN_VALUE;
while(p!=null){ HashMap<Integer, HashSet<TreeNode>> reversed = new HashMap<>();
result = p;
p = p.left; for(Map.Entry<TreeNode, Integer> entry: map.entrySet()){
} If the tree is balanced, the time complexity is the height of the tree - O(log(n)). In the worst cast, the time is min = Math.min(min, entry.getValue());
O(n). Space complexity is constant. max = Math.max(max, entry.getValue());
if(result != null){
return result; HashSet<TreeNode> set = reversed.getOrDefault(entry.getValue(), new HashSet<TreeNode>());
} set.add(entry.getKey());
reversed.put(entry.getValue(), set);
//case 2: right child is null -> go up to the parent, }
//until the node is a left child, return the parent
p = x;
List<List<Integer>> result = new ArrayList<List<Integer>>();
while(p!=null){ for(int i=min; i<=max; i++){
if(p.parent!=null && p.parent.left==p){ HashSet<TreeNode> set = reversed.get(i);
return p.parent; ArrayList<Integer> l = new ArrayList<>();
} for(TreeNode td: set){
p = p.parent; l.add(td.val);
} }
result.add(l);
return null; }
}
return result;
}

private int helper(TreeNode root, HashMap<TreeNode, Integer> map){

376 | 568 Program Creek 377 | 568 378 | 568


197 Find Leaves of Binary Tree 198 Largest BST Subtree

if(root==null){ }
return 0; }
}

int left = helper(root.left, map);


int right = helper(root.right, map); 198 Largest BST Subtree
int order = Math.max(left, right)+1;
map.put(root, order); Given a binary tree, find the largest subtree which is a Binary Search Tree (BST), where largest means subtree
return order; with largest number of nodes in it.
}

198.1 Java Solution

197.2 Java Solution 2 - Optomized


class Wrapper{
int size;
The key to solve this problem is converting the problem to be finding the index of the element in the result list.
int lower, upper;
Then this is a typical DFS problem on trees.
boolean isBST;

public List<List<Integer>> findLeaves(TreeNode root) {


public Wrapper(){
List<List<Integer>> result = new ArrayList<List<Integer>>();
lower = Integer.MAX_VALUE;
helper(result, root);
upper = Integer.MIN_VALUE;
return result;
isBST = false;
}
size = 0;
}
// traverse the tree bottom-up recursively
}
private int helper(List<List<Integer>> list, TreeNode root){
public class Solution {
if(root==null)
public int largestBSTSubtree(TreeNode root) {
return -1;
return helper(root).size;
}
int left = helper(list, root.left);
int right = helper(list, root.right);
public Wrapper helper(TreeNode node){
int curr = Math.max(left, right)+1;
Wrapper curr = new Wrapper();

// the first time this code is reached is when curr==0,


if(node == null){
//since the tree is bottom-up processed.
curr.isBST= true;
if(list.size()<=curr){
return curr;
list.add(new ArrayList<Integer>());
}
}

Wrapper l = helper(node.left);
list.get(curr).add(root.val);
Wrapper r = helper(node.right);

return curr;
//current subtree’s boundaries
}
curr.lower = Math.min(node.val, l.lower);
curr.upper = Math.max(node.val, r.upper);

//check left and right subtrees are BST or not


//check left’s upper again current’s value and right’s lower against current’s value
if(l.isBST && r.isBST && l.upper<=node.val && r.lower>=node.val){
curr.size = l.size+r.size+1;
curr.isBST = true;
}else{
curr.size = Math.max(l.size, r.size);
curr.isBST = false;
}

return curr;

Program Creek 379 | 568 380 | 568 Program Creek 381 | 568
199 Implement Trie (Prefix Tree) 199 Implement Trie (Prefix Tree)

TrieNode t; class TrieNode {


if(children.containsKey(c)){ TrieNode[] arr;
t = children.get(c); boolean isEnd;
}else{ // Initialize your data structure here.
199 Implement Trie (Prefix Tree) t = new TrieNode(c); public TrieNode() {
children.put(c, t); this.arr = new TrieNode[26];
} }
Implement a trie with insert, search, and startsWith methods.
children = t.children; }

199.1 Java Solution 1 //set leaf node public class Trie {


if(i==word.length()-1) private TrieNode root;
A trie node should contains the character, its children and the flag that marks if it is a leaf node. You can use the t.isLeaf = true;
trie in the following diagram to walk though the Java solution. } public Trie() {
} root = new TrieNode();
}
// Returns if the word is in the trie.
public boolean search(String word) { // Inserts a word into the trie.
TrieNode t = searchNode(word); public void insert(String word) {
TrieNode p = root;
if(t != null && t.isLeaf) for(int i=0; i<word.length(); i++){
return true; char c = word.charAt(i);
else int index = c-’a’;
return false; if(p.arr[index]==null){
} TrieNode temp = new TrieNode();
p.arr[index]=temp;
// Returns if there is any word in the trie p = temp;
// that starts with the given prefix. }else{
public boolean startsWith(String prefix) { p=p.arr[index];
if(searchNode(prefix) == null) }
return false; }
else p.isEnd=true;
class TrieNode { }
return true;
char c;
}
HashMap<Character, TrieNode> children = new HashMap<Character, TrieNode>(); // Returns if the word is in the trie.
boolean isLeaf; public boolean search(String word) {
public TrieNode searchNode(String str){
Map<Character, TrieNode> children = root.children; TrieNode p = searchNode(word);
public TrieNode() {} if(p==null){
TrieNode t = null;
for(int i=0; i<str.length(); i++){ return false;
public TrieNode(char c){ }else{
char c = str.charAt(i);
this.c = c; if(p.isEnd)
if(children.containsKey(c)){
} return true;
t = children.get(c);
} }
children = t.children;
}else{
return null; return false;
public class Trie {
} }
private TrieNode root;
}
// Returns if there is any word in the trie
public Trie() {
return t; // that starts with the given prefix.
root = new TrieNode();
} public boolean startsWith(String prefix) {
}
} TrieNode p = searchNode(prefix);
if(p==null){
// Inserts a word into the trie.
return false;
public void insert(String word) {
}else{
HashMap<Character, TrieNode> children = root.children;
return true;
199.2 Java Solution 2 - Improve Performance by Using an Array
}
for(int i=0; i<word.length(); i++){
}
char c = word.charAt(i); Each trie node can only contains ’a’-’z’ characters. So we can use a small array to store the character.

382 | 568 Program Creek 383 | 568 Program Creek 384 | 568
199 Implement Trie (Prefix Tree) 200 Add and Search Word Data structure design

public TrieNode searchNode(String s){ children = t.children;


TrieNode p = root;
for(int i=0; i<s.length(); i++){ if(i == word.length()-1){
char c= s.charAt(i); t.isLeaf = true;
int index = c-’a’; 200 Add and Search Word Data structure design }
if(p.arr[index]!=null){ }
p = p.arr[index]; }
}else{ Design a data structure that supports the following two operations:
return null; // Returns if the word is in the data structure. A word could
void addWord(word)
} // contain the dot character ’.’ to represent any one letter.
bool search(word)
} public boolean search(String word) {
return dfsSearch(root.children, word, 0);
if(p==root) search(word) can search a literal word or a regular expression string containing only letters a-z or .. A . means
return null; it can represent any one letter. }

return p; public boolean dfsSearch(HashMap<Character, TrieNode> children, String word, int start) {
} 200.1 Java Solution 1 if(start == word.length()){
} if(children.size()==0)
This problem is similar with Implement Trie. The solution 1 below uses the same definition of a trie node. To return true;
If the same words can be inserted more than once, what do you need to change to make it work? handle the "." case for this problem, we need to search all possible paths, instead of one path. else
TrieNode return false;
}
class TrieNode{
char c; char c = word.charAt(start);
HashMap<Character, TrieNode> children = new HashMap<Character, TrieNode>();
boolean isLeaf; if(children.containsKey(c)){
if(start == word.length()-1 && children.get(c).isLeaf){
public TrieNode() {} return true;
}
public TrieNode(char c){
this.c = c; return dfsSearch(children.get(c).children, word, start+1);
} }else if(c == ’.’){
} boolean result = false;
for(Map.Entry<Character, TrieNode> child: children.entrySet()){
WordDictionary if(start == word.length()-1 && child.getValue().isLeaf){
return true;
public class WordDictionary { }
private TrieNode root;
//if any path is true, set result to be true;
public WordDictionary(){ if(dfsSearch(child.getValue().children, word, start+1)){
root = new TrieNode(); result = true;
} }
}
// Adds a word into the data structure.
public void addWord(String word) { return result;
HashMap<Character, TrieNode> children = root.children; }else{
return false;
for(int i=0; i<word.length(); i++){ }
char c = word.charAt(i); }
}
TrieNode t = null;
if(children.containsKey(c)){
t = children.get(c);
}else{ 200.2 Java Solution 2 - Using Array Instead of HashMap
t = new TrieNode(c);
children.put(c,t);
} class TrieNode{

Program Creek 385 | 568 386 | 568 Program Creek 387 | 568
200 Add and Search Word Data structure design 200 Add and Search Word Data structure design

TrieNode[] arr; if (tResult)


boolean isLeaf; return true;
} else {
public TrieNode(){ int index = c - ’a’;
arr = new TrieNode[26];
} if (p.arr[index] != null) { 201 Range Sum Query Mutable
} return dfsSearch(p.arr[index], word, start + 1);
} else {
public class WordDictionary { return false; Given an integer array nums, find the sum of the elements between indices i and j (i ≤ j), inclusive. The update(i,
TrieNode root; } val) function modifies nums by updating the element at index i to val.
}
public WordDictionary(){
root = new TrieNode(); return false; 201.1 Java Solution 1 - Segment Tree
} }
// Adds a word into the data structure. }
public void addWord(String word) {
TrieNode p= root;
for(int i=0; i<word.length(); i++){
char c=word.charAt(i);
int index = c-’a’;
if(p.arr[index]==null){
TrieNode temp = new TrieNode();
p.arr[index]=temp;
p=temp;
}else{
p=p.arr[index];
}
}

p.isLeaf=true;
}

// Returns if the word is in the data structure. A word could


// contain the dot character ’.’ to represent any one letter.
public boolean search(String word) {
return dfsSearch(root, word, 0);
}

public boolean dfsSearch(TrieNode p, String word, int start) {


if (p.isLeaf && start == word.length())
return true;
class TreeNode{
if (start >= word.length()) int start;
return false; int end;
int sum;
char c = word.charAt(start); TreeNode leftChild;
TreeNode rightChild;
if (c == ’.’) {
boolean tResult = false; public TreeNode(int left, int right, int sum){
for (int j = 0; j < 26; j++) { this.start=left;
if (p.arr[j] != null) { this.end=right;
if (dfsSearch(p.arr[j], word, start + 1)) { this.sum=sum;
tResult = true; }
break; public TreeNode(int left, int right){
} this.start=left;
} this.end=right;
} this.sum=0;
}

Program Creek 388 | 568 Program Creek 389 | 568 390 | 568
201 Range Sum Query Mutable 201 Range Sum Query Mutable 201 Range Sum Query Mutable

} }
if(i==j){ return sum;
public class NumArray { return new TreeNode(i, j, nums[i]); }
TreeNode root = null; } }

public NumArray(int[] nums) { TreeNode current = new TreeNode(i, j);


if(nums==null || nums.length==0)
return; int mid = i + (j-i)/2;

this.root = buildTree(nums, 0, nums.length-1); current.leftChild = buildTree(nums, i, mid);


} current.rightChild = buildTree(nums, mid+1, j);

void update(int i, int val) { current.sum = current.leftChild.sum+current.rightChild.sum;


updateHelper(root, i, val);
} return current;
}
void updateHelper(TreeNode root, int i, int val){ }
if(root==null)
return;

201.2 Java Solution 2 - Binary Index Tree / Fenwick Tree


int mid = root.start + (root.end-root.start)/2; Here is a perfect video to show how binary index tree works. In addition, my notes at the end of the post may
if(i<=mid){ also help.
updateHelper(root.leftChild, i, val);
}else{ public class NumArray {
updateHelper(root.rightChild, i, val);
} int[] btree;
int[] arr;
if(root.start==root.end&& root.start==i){
root.sum=val; public NumArray(int[] nums) {
return; btree = new int[nums.length+1];
} arr = nums;

root.sum=root.leftChild.sum+root.rightChild.sum; for(int i=0; i<nums.length; i++){


} add(i+1, nums[i]);
}
public int sumRange(int i, int j) { }
return sumRangeHelper(root, i, j);
} void add(int i, int val) {
for(int j=i; j<btree.length; j=j+(j&(-j)) ){
public int sumRangeHelper(TreeNode root, int i, int j){ btree[j] += val;
if(root==null || j<root.start || i > root.end ||i>j ) }
return 0; }

if(i<=root.start && j>=root.end){ void update(int i, int val) {


return root.sum; add(i+1, val-arr[i]);
} arr[i]=val;
int mid = root.start + (root.end-root.start)/2; }
int result = sumRangeHelper(root.leftChild, i, Math.min(mid, j))
+sumRangeHelper(root.rightChild, Math.max(mid+1, i), j); public int sumRange(int i, int j) {
return sumHelper(j+1)-sumHelper(i);
return result; }
}
public int sumHelper(int i){
public TreeNode buildTree(int[] nums, int i, int j){ int sum=0;
if(nums==null || nums.length==0|| i>j) for(int j=i; j>=1; j=j-(j&(-j))){
return null; sum += btree[j];

Program Creek 391 | 568 Program Creek 392 | 568 Program Creek 393 | 568
202 The Skyline Problem

if (!a.isStart && !b.isStart) {


return Integer.compare(a.height, b.height);
}

return a.isStart ? -1 : 1;
202 The Skyline Problem } 203 Implement Stack using Queues
});

// process edges Implement the following operations of a stack using queues. push(x) – Push element x onto stack. pop() –
202.1 Analysis
PriorityQueue<Integer> heightHeap = new PriorityQueue<Integer>(10, Collections.reverseOrder()); Removes the element on top of the stack. top() – Get the top element. empty() – Return whether the stack is
This problem is essentially a problem of processing 2*n edges. Each edge has a x-axis value and a height value. empty.
The key part is how to use the height heap to process each edge. for (Edge edge : edges) { Note: only standard queue operations are allowed, i.e., poll(), offer(), peek(), size() and isEmpty() in Java.
if (edge.isStart) {
if (heightHeap.isEmpty() || edge.height > heightHeap.peek()) {

202.2 Java Solution result.add(new int[] { edge.x, edge.height }); 203.1 Analysis
}
heightHeap.add(edge.height); This problem can be solved by using two queues.
class Edge { } else {
int x; heightHeap.remove(edge.height);
int height; 203.2 Java Solution
boolean isStart; if(heightHeap.isEmpty()){
result.add(new int[] {edge.x, 0});
public Edge(int x, int height, boolean isStart) { }else if(edge.height > heightHeap.peek()){ class MyStack {
this.x = x; result.add(new int[]{edge.x, heightHeap.peek()}); LinkedList<Integer> queue1 = new LinkedList<Integer>();
this.height = height; } LinkedList<Integer> queue2 = new LinkedList<Integer>();
this.isStart = isStart; }
} } // Push element x onto stack.
} public void push(int x) {
return result; if(empty()){
} queue1.offer(x);
public List<int[]> getSkyline(int[][] buildings) { }else{
List<int[]> result = new ArrayList<int[]>(); if(queue1.size()>0){
queue2.offer(x);
if (buildings == null || buildings.length == 0 int size = queue1.size();
|| buildings[0].length == 0) { while(size>0){
return result; queue2.offer(queue1.poll());
} size--;
}
List<Edge> edges = new ArrayList<Edge>(); }else if(queue2.size()>0){
queue1.offer(x);
// add all left/right edges int size = queue2.size();
for (int[] building : buildings) { while(size>0){
Edge startEdge = new Edge(building[0], building[2], true); queue1.offer(queue2.poll());
edges.add(startEdge); size--;
Edge endEdge = new Edge(building[1], building[2], false); }
edges.add(endEdge); }
} }
}
// sort edges
Collections.sort(edges, new Comparator<Edge>() { // Removes the element on top of the stack.
public int compare(Edge a, Edge b) { public void pop() {
if (a.x != b.x) if(queue1.size()>0){
return Integer.compare(a.x, b.x); queue1.poll();
}else if(queue2.size()>0){
if (a.isStart && b.isStart) { queue2.poll();
return Integer.compare(b.height, a.height); }
} }

394 | 568 Program Creek 395 | 568 396 | 568


203 Implement Stack using Queues

// Get the top element.


public int top() {
if(queue1.size()>0){
return queue1.peek();
}else if(queue2.size()>0){
return queue2.peek(); 204 Implement Queue using Stacks 205 Implement a Stack Using an Array in Java
}
return 0;
} Implement the following operations of a queue using stacks. This post shows how to implement a stack by using an array.
push(x) – Push element x to the back of queue. pop() – Removes the element from in front of queue. peek() – The requirements of the stack are: 1) the stack has a constructor which accepts a number to initialize its size,
// Return whether the stack is empty. Get the front element. empty() – Return whether the queue is empty. 2) the stack can hold any type of elements, 3) the stack has a push() and a pop() method.
public boolean empty() {
return queue1.isEmpty() & queue2.isEmpty();
} 204.1 Java Solution 205.1 A Simple Stack Implementation
}

class MyQueue { public class Stack<E> {


private E[] arr = null;
Stack<Integer> temp = new Stack<Integer>(); private int CAP;
Stack<Integer> value = new Stack<Integer>(); private int top = -1;
private int size = 0;
// Push element x to the back of queue.
public void push(int x) { @SuppressWarnings("unchecked")
if(value.isEmpty()){ public Stack(int cap) {
value.push(x); this.CAP = cap;
}else{ this.arr = (E[]) new Object[cap];
while(!value.isEmpty()){ }
temp.push(value.pop());
} public E pop() {
if(this.size == 0){
value.push(x); return null;
}
while(!temp.isEmpty()){
value.push(temp.pop()); this.size--;
} E result = this.arr[top];
} this.arr[top] = null;//prevent memory leaking
} this.top--;

// Removes the element from in front of queue. return result;


public void pop() { }
value.pop();
} public boolean push(E e) {
if (isFull())
// Get the front element. return false;
public int peek() {
return value.peek(); this.size++;
} this.arr[++top] = e;

// Return whether the queue is empty. return true;


public boolean empty() { }
return value.isEmpty();
} public boolean isFull() {
} if (this.size == this.CAP)
return false;
return true;
}

public String toString() {

Program Creek 397 | 568 398 | 568 399 | 568


205 Implement a Stack Using an Array in Java 206 Implement a Queue using an Array in Java

if(this.size==0){ E result = arr[tail];


return null; arr[tail] = null;
} size--;
tail = (tail+1)%arr.length;
StringBuilder sb = new StringBuilder();
for(int i=0; i<this.size; i++){ 206 Implement a Queue using an Array in Java if (size == 0) {
sb.append(this.arr[i] + ", "); head = -1;
} tail = -1;
There following Java code shows how to implement a queue without using any extra data structures in Java. We }
sb.setLength(sb.length()-2); can implement a queue by using an array.
return sb.toString(); return true;
} }

public static void main(String[] args) { E peek(){


if(size==0)
Stack<String> stack = new Stack<String>(11); return null;
stack.push("hello");
stack.push("world"); return arr[tail];
}
System.out.println(stack);
public int size() {
stack.pop(); return this.size;
System.out.println(stack); import java.lang.reflect.Array; }
import java.util.Arrays;
stack.pop(); public String toString() {
System.out.println(stack); public class Queue<E> { return Arrays.toString(this.arr);
} }
} E[] arr;
int head = -1; public static void main(String[] args) {
Output: int tail = -1; Queue<Integer> q = new Queue<Integer>(Integer.class, 5);
int size; q.push(1);
hello, world q.push(2);
hello q.push(3);
public Queue(Class<E> c, int size) {
null q.push(4);
E[] newInstance = (E[]) Array.newInstance(c, size);
this.arr = newInstance; q.push(5);
This example is used twice in "Effective Java". In the first place, the stack example is used to illustrate memory this.size = 0; q.pop();
leak. In the second place, the example is used to illustrate when we can suppress unchecked warnings. } q.push(6);
You may check out how to implement a queue by using an array. System.out.println(q);
boolean push(E e) { }
if (size == arr.length) }
return false;

head = (head + 1) % arr.length;


arr[head] = e;
size++;

if(tail == -1){
tail = head;
}

return true;
}

boolean pop() {
if (size == 0) {
return false;
}

Program Creek 400 | 568 401 | 568 Program Creek 402 | 568
207 Evaluate Reverse Polish Notation 207 Evaluate Reverse Polish Notation

Stack<String> stack = new Stack<String>(); stack.push(String.valueOf(a+b));


break;
for (String t : tokens) { case 1:
if (!operators.contains(t)) { //push to stack if it is a number stack.push(String.valueOf(b-a));
stack.push(t); break;
207 Evaluate Reverse Polish Notation } else {//pop numbers from stack if it is an operator case 2:
int a = Integer.valueOf(stack.pop()); stack.push(String.valueOf(a*b));
int b = Integer.valueOf(stack.pop()); break;
Evaluate the value of an arithmetic expression in Reverse Polish Notation. Valid operators are +, -, *, /. Each switch (t) { case 3:
operand may be an integer or another expression. For example: case "+": stack.push(String.valueOf(b/a));
stack.push(String.valueOf(a + b)); break;
["2", "1", "+", "3", "*"] -> ((2 + 1) * 3) -> 9 break; }
["4", "13", "5", "/", "+"] -> (4 + (13 / 5)) -> 6 case "-": }
stack.push(String.valueOf(b - a)); }
break;
case "*": returnValue = Integer.valueOf(stack.pop());
207.1 Naive Approach stack.push(String.valueOf(a * b));
break; return returnValue;
This problem can be solved by using a stack. We can loop through each element in the given array. When it is case "/":
a number, push it to the stack. When it is an operator, pop two numbers from the stack, do the calculation, and stack.push(String.valueOf(b / a)); }
push back the result. break; }
}
}
}

returnValue = Integer.valueOf(stack.pop());

return returnValue;
}
}

The problem is that switch string statement is only available from JDK 1.7. Leetcode apparently use a JDK
version below 1.7.

207.2 Accepted Solution


If you want to use switch statement, you can convert the above by using the following code which use the index
of a string "+-*/".

public class Solution {


public int evalRPN(String[] tokens) {

int returnValue = 0;

The following is the code. However, this code contains compilation errors in leetcode. Why? String operators = "+-*/";

public class Test { Stack<String> stack = new Stack<String>();

public static void main(String[] args) throws IOException { for(String t : tokens){


String[] tokens = new String[] { "2", "1", "+", "3", "*" }; if(!operators.contains(t)){
System.out.println(evalRPN(tokens)); stack.push(t);
} }else{
int a = Integer.valueOf(stack.pop());
public static int evalRPN(String[] tokens) { int b = Integer.valueOf(stack.pop());
int returnValue = 0; int index = operators.indexOf(t);
String operators = "+-*/"; switch(index){
case 0:

403 | 568 Program Creek 404 | 568 Program Creek 405 | 568
208 Valid Parentheses 209 Longest Valid Parentheses 210 Min Stack
Given a string containing just the characters ’(’, ’)’, ’’, ’’, ’[’ and ’]’, determine if the input string is valid. The brackets Given a string containing just the characters ’(’ and ’)’, find the length of the longest valid (well-formed) paren- Design a stack that supports push, pop, top, and retrieving the minimum element in constant time.
must close in the correct order, "()" and "()[]" are all valid but "(]" and "([)]" are not. theses substring. push(x) – Push element x onto stack. pop() – Removes the element on top of the stack. top() – Get the top
For "(()", the longest valid parentheses substring is "()", which has length = 2. Another example is ")()())", where element. getMin() – Retrieve the minimum element in the stack.
the longest valid parentheses substring is "()()", which has length = 4.
208.1 Analysis
210.1 Java Solution
A typical problem which can be solved by using a stack data structure. 209.1 Java Solution
To make constant time of getMin(), we need to keep track of the minimum element for each element in the stack.
A stack can be used to track and reduce pairs. Since the problem asks for length, we can put the index into the Define an element class that holds element value, min value, and pointer to elements below it.
208.2 Java Solution stack along with the character. For coding simplicity purpose, we can use 0 to respresnt ( and 1 to represent ).
class Elem{
This problem is similar with Valid Parentheses, which can also be solved by using a stack.
public int value;
public static boolean isValid(String s) { public int min;
public int longestValidParentheses(String s) {
HashMap<Character, Character> map = new HashMap<Character, Character>(); public Elem next;
Stack<int[]> stack = new Stack<>();
map.put(’(’, ’)’);
int result = 0;
map.put(’[’, ’]’); public Elem(int value, int min){
map.put(’{’, ’}’); this.value = value;
for(int i=0; i<s.length(); i++){
char c = s.charAt(i); this.min = min;
Stack<Character> stack = new Stack<Character>(); }
if(c==’)’){
if(!stack.isEmpty() && stack.peek()[0]==0){ }
for (int i = 0; i < s.length(); i++) {
stack.pop();
char curr = s.charAt(i); public class MinStack {
result = Math.max(result, i-(stack.isEmpty()?-1:stack.peek()[1]));
}else{ public Elem top;
if (map.keySet().contains(curr)) {
stack.push(new int[]{1, i});
stack.push(curr); /** initialize your data structure here. */
}
} else if (map.values().contains(curr)) { public MinStack() {
}else{
if (!stack.empty() && map.get(stack.peek()) == curr) {
stack.push(new int[]{0, i});
stack.pop(); }
}
} else {
}
return false; public void push(int x) {
} if(top == null){
return result;
} top = new Elem(x, x);
}
} }else{
Elem e = new Elem(x, Math.min(x,top.min));
return stack.empty(); e.next = top;
} top = e;
}

public void pop() {


if(top == null)
return;
Elem temp = top.next;
top.next = null;
top = temp;

public int top() {

406 | 568 407 | 568 408 | 568


210 Min Stack

if(top == null)
return -1;
return top.value;
}

public int getMin() { 211 Max Chunks To Make Sorted 212 Maximal Rectangle
if(top == null)
return -1;
return top.min; Given an array arr that is a permutation of [0, 1, ..., arr.length - 1], we split the array into some number of "chunks" Given a 2D binary matrix filled with 0’s and 1’s, find the largest rectangle containing all ones and return its area.
} (partitions), and individually sort each chunk. After concatenating them, the result equals the sorted array.
} What is the most number of chunks we could have made?
For example, given [2,0,1], the method returns 0, as there can only be one chunk. 212.1 Analysis
This problem can be converted to the "Largest Rectangle in Histogram" problem.
211.1 Analysis
The key to solve this problem is using a stack to track the existing chunk. Each chunk is represented a min and 212.2 Java Solution
max number. Each chunk is essentially an interval and the interval can not overlap.
public int maximalRectangle(char[][] matrix) {
int m = matrix.length;
211.2 Java Solution int n = m == 0 ? 0 : matrix[0].length;
int[][] height = new int[m][n + 1];
public int maxChunksToSorted(int[] arr) {
int maxArea = 0;
if(arr==null||arr.length==0){
for (int i = 0; i < m; i++) {
return 0;
for (int j = 0; j < n; j++) {
}
if (matrix[i][j] == ’0’) {
height[i][j] = 0;
// use [min,max] for each chunk
} else {
Stack<int[]> stack = new Stack<int[]>();
height[i][j] = i == 0 ? 1 : height[i - 1][j] + 1;
}
for(int i=0; i<arr.length; i++){
}
int min=arr[i];
}
int max=arr[i];

for (int i = 0; i < m; i++) {


while(!stack.isEmpty()){
int area = maxAreaInHist(height[i]);
int[] top = stack.peek();
if (area > maxArea) {
maxArea = area;
if(arr[i] < top[1]){
}
min=Math.min(top[0], min);
}
max=Math.max(max, top[1]);
stack.pop();
return maxArea;
}else{
}
break;
}
private int maxAreaInHist(int[] height) {
}
Stack<Integer> stack = new Stack<Integer>();
stack.push(new int[]{min,max});
int i = 0;
}
int max = 0;
return stack.size();
while (i < height.length) {
}
if (stack.isEmpty() || height[stack.peek()] <= height[i]) {
stack.push(i++);
Time complexity is O(n).
} else {
int t = stack.pop();
max = Math.max(max, height[t]
* (stack.isEmpty() ? i : i - stack.peek() - 1));

Program Creek 409 | 568 410 | 568 411 | 568


212 Maximal Rectangle 213 Mini Parser

} NestedInteger top = stack.pop();


} if(stack.isEmpty()){
return top;
return max; }else{
} stack.peek().add(top);
213 Mini Parser }

break;
213.1 Given a nested list of integers represented as a string, case ’,’:
if(sb.length()>0){ //hande case "123," not "[456],"
implement a parser to deserialize it. Each element is either an stack.peek().add(new NestedInteger(Integer.parseInt(sb.toString())));
sb=sb.delete(0, sb.length());
integer, or a list – whose elements may also be integers or other }
lists.
break;
Note: You may assume that the string is well-formed:
default: //digits
• String is non-empty. sb.append(c);
• String does not contain white spaces. }
}
• String contains only digits and "[],"
//handle case "123"
For example,
if(sb.length()>0){
Given s = "[123,[456,[789]]]", return new NestedInteger(Integer.parseInt(sb.toString()));
}
Return a NestedInteger object containing a nested list with 2 elements:
return null;
1. An integer containing value 123. }
2. A nested list containing two elements:
i. An integer containing value 456.
ii. A nested list with one element:
a. An integer containing value 789.

213.2 Java Solution


To solve this problem, we should add more example to make clear what is the expected output. For example, s =
"[123,[456],789]" is a legal input.

public NestedInteger deserialize(String s) {


Stack<NestedInteger> stack = new Stack<>();
StringBuilder sb = new StringBuilder();

for(int i=0; i<s.length(); i++){


char c = s.charAt(i);
switch(c){
case ’[’:
NestedInteger ni = new NestedInteger();
stack.push(ni);
break;

case ’]’:
if(sb.length()>0){ //123, not [456],
stack.peek().add(new NestedInteger(Integer.parseInt(sb.toString())));
sb=sb.delete(0, sb.length());
}

Program Creek 412 | 568 413 | 568 Program Creek 414 | 568
214 Flatten Nested List Iterator

Stack<Iterator<NestedInteger>> stack = new Stack<Iterator<NestedInteger>>();


Integer current;

public NestedIterator(List<NestedInteger> nestedList) {


if(nestedList==null)
214 Flatten Nested List Iterator return; 215 Nested List Weight Sum
stack.push(nestedList.iterator());
Given a nested list of integers, implement an iterator to flatten it. Each element is either an integer, or a list – } Given a nested list of integers, return the sum of all integers in the list weighted by their depth.
whose elements may also be integers or other lists. Each element is either an integer, or a list – whose elements may also be integers or other lists.
For example, given the list [[1,1],2,[1,1]], by calling next repeatedly until hasNext returns false, the order of @Override Example 1: Given the list [[1,1],2,[1,1]], return 10. (four 1’s at depth 2, one 2 at depth 1)
elements returned by next should be: [1,1,2,1,1]. public Integer next() {
Integer result = current;
current = null; 215.1 Java Solution 1 - Recursive
214.1 Java Solution 1 return result;
}
public int depthSum(List<NestedInteger> nestedList) {
public class NestedIterator implements Iterator<Integer> { @Override return helper(nestedList, 1);
Stack<NestedInteger> stack = new Stack<NestedInteger>(); public boolean hasNext() { }
while(!stack.isEmpty() && current==null){
public NestedIterator(List<NestedInteger> nestedList) { Iterator<NestedInteger> top = stack.peek(); public int helper(List<NestedInteger> nestedList, int depth){
if(nestedList==null) if(!top.hasNext()){ if(nestedList==null||nestedList.size()==0)
return; stack.pop(); return 0;
continue;
for(int i=nestedList.size()-1; i>=0; i--){ } int sum=0;
stack.push(nestedList.get(i)); for(NestedInteger ni: nestedList){
} NestedInteger n = top.next(); if(ni.isInteger()){
} if(n.isInteger()){ sum += ni.getInteger() * depth;
current = n.getInteger(); }else{
@Override return true; sum += helper(ni.getList(), depth+1);
public Integer next() { }else{ }
return stack.pop().getInteger(); stack.push(n.getList().iterator()); }
} }
} return sum;
@Override }
public boolean hasNext() { return false;
while(!stack.isEmpty()){ }
NestedInteger top = stack.peek(); }
if(top.isInteger()){ 215.2 Java Solution 2 - Iterative
return true;
}else{
stack.pop(); public int depthSum(List<NestedInteger> nestedList) {
for(int i=top.getList().size()-1; i>=0; i--){ int sum=0;
stack.push(top.getList().get(i));
} LinkedList<NestedInteger> queue = new LinkedList<NestedInteger>();
} LinkedList<Integer> depth = new LinkedList<Integer>();
}
for(NestedInteger ni: nestedList){
return false; queue.offer(ni);
} depth.offer(1);
} }

while(!queue.isEmpty()){
NestedInteger top = queue.poll();
214.2 Java Solution 2 int dep = depth.poll();

if(top.isInteger()){
public class NestedIterator implements Iterator<Integer> { sum += dep*top.getInteger();

415 | 568 Program Creek 416 | 568 417 | 568


215 Nested List Weight Sum 216 Nested List Weight Sum II

}else{ }
for(NestedInteger ni: top.getList()){
queue.offer(ni); // calcualte sum
depth.offer(dep+1); int result=0;
} for(int i=maxLayer; i>=1; i--){
} 216 Nested List Weight Sum II if(map.get(i)!=null){
} for(int v: map.get(i)){
result += v*(maxLayer-i+1);
return sum; Given a nested list of integers, return the sum of all integers in the list weighted by their depth. }
} Each element is either an integer, or a list – whose elements may also be integers or other lists. }
Different from the previous question where weight is increasing from root to leaf, now the weight is defined }
from bottom up. i.e., the leaf level integers have weight 1, and the root level integers have the largest weight.
Example 1: Given the list [[1,1],2,[1,1]], return 8. (four 1’s at depth 1, one 2 at depth 2) return result;
Example 2: Given the list [1,[4,[6]]], return 17. (one 1 at depth 3, one 4 at depth 2, and one 6 at depth 1; 1*3 + }
4*2 + 6*1 = 17)

216.1 Java Solution

public int depthSumInverse(List<NestedInteger> nestedList) {


if(nestedList==null||nestedList.size()==0)
return 0;

HashMap<Integer, ArrayList<Integer>> map = new HashMap<Integer, ArrayList<Integer>>();

//two stacks: one is for processing nested integer, the other is for tracking layers.
Stack<NestedInteger> stack = new Stack<NestedInteger>();
Stack<Integer> layers = new Stack<Integer>();

//put all NestedIntegers to Stack and record its layer to be 1


for(NestedInteger ni: nestedList){
stack.push(ni);
layers.push(1);
}

int maxLayer=Integer.MIN_VALUE;

while(!stack.isEmpty()){
NestedInteger top = stack.pop();
int topLayer = layers.pop();

maxLayer=Math.max(maxLayer, topLayer);

if(top.isInteger()){
if(map.containsKey(topLayer)){
map.get(topLayer).add(top.getInteger());
}else{
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(top.getInteger());
map.put(topLayer, list);
}
}else{
for(NestedInteger ni: top.getList()){
stack.push(ni);
layers.push(topLayer+1);
}
}

Program Creek 418 | 568 419 | 568 Program Creek 420 | 568
217 Decode String

Stack<Node> stack = new Stack<Node>();

stack.push(new Node(1));

String t = "";
217 Decode String while (i < s.length()) { 218 Evaluate math expression with plus, minus
char c = s.charAt(i);

Given an encoded string, return it’s decoded string.


and parentheses
// new Node
The encoding rule is: k[encoded_string], where the encoded_string inside the square brackets is being repeated if (c >= ’0’ && c <= ’9’) {
exactly k times. Note that k is guaranteed to be a positive integer. t += c; Given a string of math expression, such as 1-(2+3), evaluate the value. The expression contains only digits, +, -
You may assume that the input string is always valid; No extra white spaces, square brackets are well-formed, and parentheses.
etc. } else if (c == ’[’) {
Furthermore, you may assume that the original data does not contain any digits and that digits are only for if (t.length() > 0) {
those repeat numbers, k. For example, there won’t be input like 3a or 2[4]. int num = Integer.parseInt(t); 218.1 Java Solution
stack.push(new Node(num));
Examples:
t = "";
s = "3[a]2[bc]", return "aaabcbc". } import java.util.ArrayList;
s = "3[a2[c]]", return "accaccacc". } else if (c == ’]’) { import java.util.Stack;
s = "2[abc]3[cd]ef", return "abcabccdcdcdef". Node top = stack.pop();
public class ExpressionEvaluator {
if (stack.isEmpty()) { static class Node {
Boolean isPositive;
} else { Integer value;
217.1 Java Solution
stack.peek().list.add(top); ArrayList<Node> list;

The key to solve this problem is convert the string to a structured data structure and recursively form the return }
public Node(boolean isPositive, Integer value) {
string.
} else { this.isPositive = isPositive;
class Node{ stack.peek().list.add(new Node(c)); this.value = value;
int num; } this.list = new ArrayList<>();
ArrayList<Node> list; }
char symbol; i++;
boolean isList; } public int evaluate() {
int sum = 0;
public Node(char s){ return getString(stack.peek()); for (Node t : list) {
symbol=s; } if (t.isPositive) {
} sum = sum + t.value;
public String getString(Node node){ } else {
public Node(int n){ String s=""; sum = sum - t.value;
list = new ArrayList<Node>(); if(node.isList){ }
isList=true; for(int i=0; i<node.num; i++){ }
num=n; for(Node t: node.list) return sum;
} s+= getString(t); }
} }
public String toString(){ }else{
String s = ""; s+=node.symbol; public static int evaluate(String s) {
if(isList){ } Stack<Node> stack = new Stack<>();
s += num + ":" + list.toString(); stack.push(new Node(true, 0));
}else{ return s;
s += symbol; } Boolean isPositive = true;
} } StringBuilder sb = null;
return s;
} for (int i = 0; i < s.length(); i++) {
} char c = s.charAt(i);
Node top = stack.peek();
public class Solution {
public String decodeString(String s) { if (c >= ’0’ && c <= ’9’) {
int i = 0; if (sb == null) {

421 | 568 Program Creek 422 | 568 423 | 568


218 Evaluate math expression with plus, minus and parentheses 219 Partition to K Equal Sum Subsets

sb = new StringBuilder(); return true;


} }
sb.append(c); buckets[i]-=nums[j];
if (i == s.length() - 1 }
|| s.charAt(i + 1) < ’0’ || s.charAt(i + 1) > ’9’) {
top.list.add(new Node( 219 Partition to K Equal Sum Subsets if(buckets[i]==0) break;//
isPositive == null ? true : isPositive, }
Integer.valueOf(sb.toString())));
isPositive = null; Given an array of integers nums and a positive integer k, find whether it’s possible to divide this array into k return false;
sb = null; non-empty subsets whose sums are all equal. }
} Example 1:
} else if (c == ’(’) { Input: nums = [4, 3, 2, 3, 5, 2, 1], k = 4 Output: True Explanation: It’s possible to divide it into 4 subsets (5), (1,
Node t = new Node(isPositive, null); 4), (2,3), (2,3) with equal sums.
isPositive = null;
top.list.add(t);
stack.push(t); 219.1 Java Solution
} else if (c == ’)’) {
int val = stack.pop().evaluate(); The easiest solution to this problem is DFS. We try to place each element to one of the bucket. The following is a
top = stack.peek(); Java solution and there is a diagram to show the execution of the helper() method using the given example. Note
top.list.get(top.list.size() - 1).value = val;
the improvement in the for loop.
} else if (c == ’-’ || c == ’+’) {
if (c == ’-’) { public boolean canPartitionKSubsets(int[] nums, int k) {
isPositive = false; int sum = 0;
} else { for(int num: nums){
isPositive = true; sum+=num;
} }
} if(sum%k!=0){
} return false;
}
return stack.peek().evaluate();
} int share = sum/k;

//sort array
public static void main(String[] args) { Arrays.sort(nums);
System.out.println(evaluate("(1-20)+3")); //-16
System.out.println(evaluate("1-(20+1-(2+3))")); //-15 int j=nums.length-1;
} if(nums[j]>share){
} return false;
}
while(j>=0 && nums[j]==share){
j--;
k--;
}

int[] buckets = new int[k];


return helper(j, nums, share, buckets);
}

//put jth number to each bucket and recursively search


public boolean helper(int j, int[] nums, int share, int[] buckets){
if(j<0){
return true;
}

for(int i=0; i<buckets.length; i++){


if(buckets[i]+nums[j]<=share){
buckets[i]+=nums[j];
if(helper(j-1, nums, share, buckets)){

Program Creek 424 | 568 425 | 568 Program Creek 426 | 568
220 Permutations 220 Permutations

result = new ArrayList<ArrayList<Integer>>(current);


}

return result;
220 Permutations }

Given a collection of numbers, return all possible permutations.

For example,
220.2 Java Solution 2 - Recursion
[1,2,3] have the following permutations:
We can also recursively solve this problem. Swap each element with each element after it.
[1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], and [3,2,1].
public List<List<Integer>> permute(int[] nums) {
List<List<Integer>> result = new ArrayList<>();
helper(0, nums, result);
220.1 Java Solution 1 - Iteration return result;
}
We can get all permutations by the following steps:
private void helper(int start, int[] nums, List<List<Integer>> result){
[1]
if(start==nums.length-1){
[2, 1]
ArrayList<Integer> list = new ArrayList<>();
[1, 2]
for(int num: nums){ Since C(n)=1+C(n-1), if we expand it, we can get time complexity is O(N!).
[3, 2, 1]
list.add(num);
[2, 3, 1]
}
[2, 1, 3]
result.add(list);
[3, 1, 2]
return;
[1, 3, 2]
}
[1, 2, 3]

for(int i=start; i<nums.length; i++){


Loop through the array, in each iteration, a new number is added to different locations of results of previous swap(nums, i, start);
iteration. Start from an empty List. helper(start+1, nums, result);
swap(nums, i, start);
public ArrayList<ArrayList<Integer>> permute(int[] num) {
}
ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();
}

//start from an empty list


private void swap(int[] nums, int i, int j){
result.add(new ArrayList<Integer>());
int temp = nums[i];
nums[i] = nums[j];
for (int i = 0; i < num.length; i++) {
nums[j] = temp;
//list of list in current iteration of the array num
}
ArrayList<ArrayList<Integer>> current = new ArrayList<ArrayList<Integer>>();

for (ArrayList<Integer> l : result) {


// # of locations to insert is largest index + 1
for (int j = 0; j < l.size()+1; j++) {
// + add num[i] to different locations
l.add(j, num[i]);

ArrayList<Integer> temp = new ArrayList<Integer>(l);


current.add(temp);

//System.out.println(temp);

// - remove num[i] add


l.remove(j);
}
}

427 | 568 Program Creek 428 | 568 Program Creek 429 | 568
221 Permutations II

221.2 Java Solution 2


Use set to maintain uniqueness:

public static ArrayList<ArrayList<Integer>> permuteUnique(int[] num) {


221 Permutations II ArrayList<ArrayList<Integer>> returnList = new ArrayList<ArrayList<Integer>>(); 222 Permutation Sequence
returnList.add(new ArrayList<Integer>());

Given a collection of numbers that might contain duplicates, return all possible unique permutations. for (int i = 0; i < num.length; i++) { The set [1,2,3,. . . ,n] contains a total of n! unique permutations.
Set<ArrayList<Integer>> currentSet = new HashSet<ArrayList<Integer>>(); By listing and labeling all of the permutations in order, We get the following sequence (ie, for n = 3):
For example, [1,1,2] have the following unique permutations: for (List<Integer> l : returnList) {
[1,1,2], [1,2,1], and [2,1,1]. for (int j = 0; j < l.size() + 1; j++) { "123"
l.add(j, num[i]); "132"
ArrayList<Integer> T = new ArrayList<Integer>(l); "213"
l.remove(j); "231"
221.1 Java Solution 1 currentSet.add(T); "312"
} "321"
Based on Permutation, we can add a set to track if an element is duplicate and no need to swap. }
returnList = new ArrayList<ArrayList<Integer>>(currentSet); Given n and k, return the kth permutation sequence. (Note: Given n will be between 1 and 9 inclusive.)
public List<List<Integer>> permuteUnique(int[] nums) { }
List<List<Integer>> result = new ArrayList<>();
helper(0, nums, result); return returnList; 222.1 Java Solution 1
return result; }
}
public class Solution {
Thanks to Milan for such a simple solution!
private void helper(int start, int[] nums, List<List<Integer>> result){ public String getPermutation(int n, int k) {
if(start==nums.length-1){
ArrayList<Integer> list = new ArrayList<>(); // initialize all numbers
for(int num: nums){ ArrayList<Integer> numberList = new ArrayList<Integer>();
list.add(num); for (int i = 1; i <= n; i++) {
} numberList.add(i);
result.add(list); }
return;
} // change k to be index
k--;
HashSet<Integer> set = new HashSet<>();
// set factorial of n
for(int i=start; i<nums.length; i++){ int mod = 1;
if(set.contains(nums[i])){ for (int i = 1; i <= n; i++) {
continue; mod = mod * i;
} }
set.add(nums[i]);
String result = "";
swap(nums, i, start);
helper(start+1, nums, result); // find sequence
swap(nums, i, start); for (int i = 0; i < n; i++) {
} mod = mod / (n - i);
} // find the right number(curIndex) of
int curIndex = k / mod;
private void swap(int[] nums, int i, int j){ // update k
int temp = nums[i]; k = k % mod;
nums[i] = nums[j];
nums[j] = temp; // get number according to curIndex
} result += numberList.get(curIndex);
// remove from list
numberList.remove(curIndex);
}

430 | 568 Program Creek 431 | 568 432 | 568


222 Permutation Sequence 223 Number of Squareful Arrays

return result.toString();
}
}

223 Number of Squareful Arrays


222.2 Java Solution 2
Given an array A of non-negative integers, the array is squareful if for every pair of adjacent elements, their sum
public class Solution { is a perfect square.
public String getPermutation(int n, int k) { Return the number of permutations of A that are squareful. Two permutations A1 and A2 differ if and only if
boolean[] output = new boolean[n]; there is some index i such that A1[i] != A2[i].
StringBuilder buf = new StringBuilder(""); Example 1:
Input: [1,17,8] Output: 2 Explanation: [1,8,17] and [17,8,1] are the valid permutations.
int[] res = new int[n];
Example 2:
res[0] = 1;
Input: [2,2,2] Output: 1
for (int i = 1; i < n; i++)
res[i] = res[i - 1] * i;
223.1 Java Solution
for (int i = n - 1; i >= 0; i--) {
int s = 1;
This problem can be solved by using the similar method of Permutation II. A set can be used to track if same
element is swapped. The major difference is that we need to check if previous adjacent two neighbors are
while (k > res[i]) { squareful.
s++;
k = k - res[i];
}

for (int j = 0; j < n; j++) {


if (j + 1 <= s && output[j]) {
s++;
}
}

output[s - 1] = true;
buf.append(Integer.toString(s));
}

return buf.toString();
class Solution {
}
int count = 0;
}

public int numSquarefulPerms(int[] A) {


Arrays.sort(A);
helper(A, 0);
return count;
}

void helper(int[] A, int start){


//the adjacent two numbers before start
if(start>1 && (!isSquareful(A[start], A[start-1]) || !isSquareful(A[start-1], A[start-2]))){
return;
}
//if start is the last, then check start with its adjancent neighbor
if(start==A.length-1 && !isSquareful(A[start], A[start-1])){
return;
}

Program Creek 433 | 568 434 | 568 Program Creek 435 | 568
223 Number of Squareful Arrays 224 Generate Parentheses

if(start==A.length-1){ diff.add(0);
count++;
return; for (int i = 0; i < 2 * n; i++) {
} ArrayList<String> temp1 = new ArrayList<String>();
ArrayList<Integer> temp2 = new ArrayList<Integer>();
HashSet<Integer> set = new HashSet<>(); 224 Generate Parentheses
for(int i=start; i<A.length; i++){ for (int j = 0; j < result.size(); j++) {
//use set to track if the same element is used String s = result.get(j);
if(set.contains(A[i])){ Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses. int k = diff.get(j);
continue; For example, given n = 3, a solution set is:
} if (i < 2 * n - 1) {
set.add(A[i]); "((()))", "(()())", "(())()", "()(())", "()()()" temp1.add(s + "(");
temp2.add(k + 1);
swap(A, i, start); }
helper(A, start+1);
swap(A, i, start); 224.1 Java Solution 1 - DFS if (k > 0 && i < 2 * n - 1 || k == 1 && i == 2 * n - 1) {
} temp1.add(s + ")");
} This solution is simple and clear. In the dfs() method, left stands for the remaining number of (, right stands for temp2.add(k - 1);
the remaining number of ). }
void swap(int[] A, int i, int j){ }
int t = A[i]; public List<String> generateParenthesis(int n) {
A[i] = A[j]; ArrayList<String> result = new ArrayList<String>(); result = new ArrayList<String>(temp1);
A[j] = t; dfs(result, "", n, n); diff = new ArrayList<Integer>(temp2);
} return result; }
}
boolean isSquareful(int a, int b){ /* return result;
double root = Math.sqrt(a+b); left and right represents the remaining number of ( and ) that need to be added. }
return (root-Math.floor(root))==0; When left > right, there are more ")" placed than "(". Such cases are wrong and the method stops.
} */
} public void dfs(ArrayList<String> result, String s, int left, int right){
if(left > right)
return;

if(left==0&&right==0){
result.add(s);
return;
}

if(left>0){
dfs(result, s+"(", left-1, right);
}

if(right>0){
dfs(result, s+")", left, right-1);
}
}

224.2 Java Solution 2


This solution looks more complicated. ,You can use n=2 to walk though the code.

public List<String> generateParenthesis(int n) {


ArrayList<String> result = new ArrayList<String>();
ArrayList<Integer> diff = new ArrayList<Integer>();

result.add("");

Program Creek 436 | 568 437 | 568 Program Creek 438 | 568
225 Combination Sum

List<Integer> list, List<List<Integer>> result){


if(sum>target){
return;
}

225 Combination Sum if(sum==target){ 226 Combination Sum II


result.add(new ArrayList<>(list));
return;
Given a set of candidate numbers (C) and a target number (T), find all unique combinations in C where the } Given a collection of candidate numbers (C) and a target number (T), find all unique combinations in C where
candidate numbers sums to T. The same repeated number may be chosen from C unlimited number of times. the candidate numbers sums to T. Each number in C may only be used ONCE in the combination.
Note: All numbers (including target) will be positive integers. Elements in a combination (a1, a2, ... , ak) must for(int i=start; i<candidates.length; i++){ Note: 1) All numbers (including target) will be positive integers. 2) Elements in a combination (a1, a2, . . . ,
be in non-descending order. (ie, a1 <= a2 <= ... <= ak). The solution set must not contain duplicate combinations. list.add(candidates[i]); ak) must be in non-descending order. (ie, a1 ≤ a2 ≤ . . . ≤ ak). 3) The solution set must not contain duplicate
For example, given candidate set 2,3,6,7 and target 7, A solution set is: helper(candidates, i, target, sum+candidates[i], list, result); combinations.
list.remove(list.size()-1);
[7] }
[2, 2, 3] } 226.1 Java Solution
This problem is an extension of Combination Sum. The difference is one number in the array can only be used
ONCE.
225.1 Java Solution
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
The first impression of this problem should be depth-first search(DFS). To solve DFS problem, recursion is a List<List<Integer>> result = new ArrayList<List<Integer>>();
normal implementation. List<Integer> curr = new ArrayList<Integer>();
The following example shows how DFS works: Arrays.sort(candidates);
helper(result, curr, 0, target, candidates);
return result;
}

public void helper(List<List<Integer>> result, List<Integer> curr, int start, int target, int[]
candidates){
if(target==0){
result.add(new ArrayList<Integer>(curr));
return;
}
if(target<0){
return;
}

int prev=-1;
for(int i=start; i<candidates.length; i++){
if(prev!=candidates[i]){ // each time start from different element
curr.add(candidates[i]);
helper(result, curr, i+1, target-candidates[i], candidates); // and use next element only
curr.remove(curr.size()-1);
prev=candidates[i];
}
}
}

public List<List<Integer>> combinationSum(int[] candidates, int target) {


List<List<Integer>> result = new ArrayList<>();
List<Integer> temp = new ArrayList<>();
helper(candidates, 0, target, 0, temp, result);
return result;
}

private void helper(int[] candidates, int start, int target, int sum,

439 | 568 Program Creek 440 | 568 441 | 568


227 Combination Sum III 228 Combination Sum IV 229 Wildcard Matching
Find all possible combinations of k numbers that add up to a number n, given that only numbers from 1 to 9 can Given an integer array with all positive numbers and no duplicates, find the number of possible combinations Implement wildcard pattern matching with support for ’?’ and ’*’.
be used and each combination should be a unique set of numbers. that add up to a positive integer target.
Ensure that numbers within the set are sorted in ascending order.
Example 1: Input: k = 3, n = 7 Output: [[1,2,4]] Example 2: Input: k = 3, n = 9 Output: [[1,2,6], [1,3,5], [2,3,4]] 229.1 Java Solution
228.1 Java Solution
To understand this solution, you can use s="aab" and p="*ab".
227.1 Analysis This problem is similar to Coin Change. It’s a typical dynamic programming problem.
public boolean isMatch(String s, String p) {
public int combinationSum4(int[] nums, int target) { int i = 0;
Related problems: Combination Sum, Combination Sum II.
if(nums==null || nums.length==0) int j = 0;
return 0; int starIndex = -1;
int iIndex = -1;
227.2 Java Solution
int[] dp = new int[target+1];
while (i < s.length()) {
public List<List<Integer>> combinationSum3(int k, int n) { dp[0]=1; if (j < p.length() && (p.charAt(j) == ’?’ || p.charAt(j) == s.charAt(i))) {
List<List<Integer>> result = new ArrayList<List<Integer>>(); ++i;
List<Integer> curr = new ArrayList<Integer>(); for(int i=0; i<=target; i++){ ++j;
helper(result, curr, k, 1, n); for(int num: nums){ } else if (j < p.length() && p.charAt(j) == ’*’) {
return result; if(i+num<=target){ starIndex = j;
} dp[i+num]+=dp[i]; iIndex = i;
} j++;
public void helper(List<List<Integer>> result, List<Integer> curr, int k, int start, int sum){ } } else if (starIndex != -1) {
if(sum<0){ } j = starIndex + 1;
return; i = iIndex+1;
} return dp[target]; iIndex++;
} } else {
if(sum==0 && curr.size()==k){ return false;
result.add(new ArrayList<Integer>(curr)); }
return; }
}
while (j < p.length() && p.charAt(j) == ’*’) {
for(int i=start; i<=9; i++){ ++j;
curr.add(i); }
helper(result, curr, k, i+1, sum-i);
curr.remove(curr.size()-1); return j == p.length();
} }
}

442 | 568 443 | 568 444 | 568


230 Regular Expression Matching 230 Regular Expression Matching

} return true;
} }
} i++;
}
return false;
230 Regular Expression Matching }
230.3 Java Solution 2 (More Readable) }

Implement regular expression matching with support for ’.’ and ’*’.
’.’ Matches any single character. ’*’ Matches zero or more of the preceding element. public boolean isMatch(String s, String p) {
The matching should cover the entire input string (not partial). // base case
The function prototype should be: bool isMatch(const char *s, const char *p) if (p.length() == 0) {
Some examples: isMatch("aa","a") return false isMatch("aa","aa") return true isMatch("aaa","aa") return false return s.length() == 0;
}
isMatch("aa", "a*") return true isMatch("aa", ".*") return true isMatch("ab", ".*") return true isMatch("aab", "c*a*b")
return true
// special case
if (p.length() == 1) {

230.1 Analysis // if the length of s is 0, return false


if (s.length() < 1) {
First of all, this is one of the most difficulty problems. It is hard to think through all different cases. The problem
return false;
should be simplified to handle 2 basic cases: }

• the second char of pattern is "*"


//if the first does not match, return false
• the second char of pattern is not "*" else if ((p.charAt(0) != s.charAt(0)) && (p.charAt(0) != ’.’)) {
return false;
For the 1st case, if the first char of pattern is not ".", the first char of pattern and string should be the same. }
Then continue to match the remaining part.
For the 2nd case, if the first char of pattern is "." or first char of pattern == the first i char of string, continue to // otherwise, compare the rest of the string of s and p.
match the remaining part. else {
return isMatch(s.substring(1), p.substring(1));
}
230.2 Java Solution 1 (Short) }

The following Java solution is accepted. // case 1: when the second char of p is not ’*’
if (p.charAt(1) != ’*’) {
public class Solution { if (s.length() < 1) {
public boolean isMatch(String s, String p) { return false;
}
if(p.length() == 0) if ((p.charAt(0) != s.charAt(0)) && (p.charAt(0) != ’.’)) {
return s.length() == 0; return false;
} else {
//p’s length 1 is special case return isMatch(s.substring(1), p.substring(1));
if(p.length() == 1 || p.charAt(1) != ’*’){ }
if(s.length() < 1 || (p.charAt(0) != ’.’ && s.charAt(0) != p.charAt(0))) }
return false;
return isMatch(s.substring(1), p.substring(1)); // case 2: when the second char of p is ’*’, complex case.
else {
}else{ //case 2.1: a char & ’*’ can stand for 0 element
int len = s.length(); if (isMatch(s, p.substring(2))) {
return true;
int i = -1; }
while(i<len && (i < 0 || p.charAt(0) == ’.’ || p.charAt(0) == s.charAt(i))){
if(isMatch(s.substring(i+1), p.substring(2))) //case 2.2: a char & ’*’ can stand for 1 or more preceding element,
return true; //so try every sub string
i++; int i = 0;
} while (i<s.length() && (s.charAt(i)==p.charAt(0) || p.charAt(0)==’.’)){
return false; if (isMatch(s.substring(i + 1), p.substring(2))) {

445 | 568 Program Creek 446 | 568 Program Creek 447 | 568
231 Expressive Words

m++;
}
while (n < s2.length() && s2.charAt(n) == s2.charAt(n - 1)) {
n++;
}
231 Expressive Words if (n - j > m - i) { 232 Get Target Number Using Number List and
return false;

Sometimes people repeat letters to represent extra feeling, such as "hello" ->"heeellooo", "hi" ->"hiiii". In these
} Arithmetic Operations
strings like "heeellooo", we have groups of adjacent letters that are all the same: "h", "eee", "ll", "ooo". res = isMatch(s1, m, s2, n);
For some given string S, a query word is stretchy if it can be made to be equal to S by any number of applica- } Given a list of numbers and a target number, write a program to determine whether the target number can be
tions of the following extension operation: choose a group consisting of characters c, and add some number of calculated by applying "+-*/" operations to the number list? You can assume () is automatically added when
characters c to the group so that the size of the group is 3 or more. res = res | isMatch(s1, i + 1, s2, j + 1); necessary.
For example, starting with "hello", we could do an extension on the group "o" to get "hellooo", but we cannot For example, given 1,2,3,4 and 21, return true. Because (1+2)*(3+4)=21
get "helloo" since the group "oo" has size less than 3. Also, we could do another extension like "ll" ->"lllll" to return res;
}
get "helllllooo". If S = "helllllooo", then the query word "hello" would be stretchy because of these two extension
operations: query = "hello" ->"hellooo" ->"helllllooo" = S. 232.1 Analysis
Given a list of query words, return the number of words that are stretchy.
Example: Input: S = "heeellooo" words = ["hello", "hi", "helo"] Output: 1 Explanation: We can extend "e" and This is a partition problem which can be solved by using depth first search.
"o" in the word "hello" to get "heeellooo". We can’t extend "helo" to get "heeellooo" because the group "ll" is not
size 3 or more.
232.2 Java Solution

231.1 Java Solution public static boolean isReachable(ArrayList<Integer> list, int target) {
if (list == null || list.size() == 0)
This problem is similar to regular expression matching. return false;

public int expressiveWords(String S, String[] words) {


int i = 0;
int count = 0;
int j = list.size() - 1;
for (String s : words) {
if (isMatch(S, 0, s, 0)) {
ArrayList<Integer> results = getResults(list, i, j, target);
count++;
}
for (int num : results) {
}
if (num == target) {
return true;
return count;
}
}
}

private boolean isMatch(String s1, int i, String s2, int j) {


return false;
if (i >= s1.length() && j >= s2.length()) {
}
return true;
} else if (i >= s1.length() || j >= s2.length()) {
public static ArrayList<Integer> getResults(ArrayList<Integer> list,
return false;
int left, int right, int target) {
}
ArrayList<Integer> result = new ArrayList<Integer>();

if (s1.charAt(i) != s2.charAt(j)) {
if (left > right) {
return false;
return result;
}
} else if (left == right) {
result.add(list.get(left));
boolean res = false;
return result;
}
if (i + 2 < s1.length()
&& s1.charAt(i + 1) == s2.charAt(j)
for (int i = left; i < right; i++) {
&& s1.charAt(i + 2) == s2.charAt(j)) {
int m = i + 2;
ArrayList<Integer> result1 = getResults(list, left, i, target);
int n = j + 1;
ArrayList<Integer> result2 = getResults(list, i + 1, right, target);
while (m < s1.length() && s1.charAt(m) == s2.charAt(j)) {

448 | 568 Program Creek 449 | 568 450 | 568


232 Get Target Number Using Number List and Arithmetic Operations

for (int x : result1) {


for (int y : result2) {
result.add(x + y);
result.add(x - y);
result.add(x * y);
if (y != 0) 233 Flip Game 234 Flip Game II
result.add(x / y);
}
} You are playing the following Flip Game with your friend: Given a string that contains only these two characters: You are playing the following Flip Game with your friend: Given a string that contains only these two characters:
} + and -, you and your friend take turns to flip two consecutive "++" into "–". The game ends when a person can + and -, you and your friend take turns to flip two consecutive "++" into "–". The game ends when a person can
no longer make a move and therefore the other person will be the winner. no longer make a move and therefore the other person will be the winner.
return result; Write a function to compute all possible states of the string after one valid move. Write a function to determine if the starting player can guarantee a win.
} For example, given s = "++++", return true. The starting player can guarantee a win by flipping the middle
"++" to become "+–+".
233.1 Java Solution

234.1 Java Solution


public List<String> generatePossibleNextMoves(String s) {
List<String> result = new ArrayList<String>();
This problem is solved by backtracking.
if(s==null) public boolean canWin(String s) {
return result; if(s==null||s.length()==0){
return false;
char[] arr = s.toCharArray(); }
for(int i=0; i<arr.length-1; i++){
if(arr[i]==arr[i+1] && arr[i]==’+’){ return canWinHelper(s.toCharArray());
arr[i]=’-’; }
arr[i+1]=’-’;
result.add(new String(arr)); public boolean canWinHelper(char[] arr){
arr[i]=’+’; for(int i=0; i<arr.length-1;i++){
arr[i+1]=’+’; if(arr[i]==’+’&&arr[i+1]==’+’){
} arr[i]=’-’;
} arr[i+1]=’-’;

return result; boolean win = canWinHelper(arr);


}
arr[i]=’+’;
arr[i+1]=’+’;

//if there is a flip which makes the other player lose, the first play wins
if(!win){
return true;
}
}
}

return false;
}

234.2 Time Complexity


Roughly, the time is n*n*...n, which is O(nn̂). The reason is each recursion takes O(n) and there are totally n
recursions.

Program Creek 451 | 568 452 | 568 453 | 568


236 Word Pattern II

public boolean wordPatternMatch(String pattern, String str) {


if(pattern.length()==0 && str.length()==0)
return true;
if(pattern.length()==0)
return false;
235 Word Pattern 236 Word Pattern II
HashMap<Character, String> map = new HashMap<Character, String>();
HashSet<String> set = new HashSet<String>();
Given a pattern and a string str, find if str follows the same pattern. Here follow means a full match, such that This is the extension problem of Word Pattern I. return helper(pattern, str, 0, 0, map, set);
there is a bijection between a letter in pattern and a non-empty word in str. 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. public boolean helper(String pattern, String str, int i, int j, HashMap<Character, String> map,
235.1 Java Solution Examples: pattern = "abab", str = "redblueredblue" should return true. pattern = "aaaa", str = "asdasdasdasd" HashSet<String> set){
should return true. pattern = "aabb", str = "xyzabcxzyabc" should return false. if(i==pattern.length() && j==str.length()){
return true;
public boolean wordPattern(String pattern, String str) {
}
String[] arr = str.split(" ");
236.1 Java Solution
if(i>=pattern.length() || j>=str.length())
//prevent out of boundary problem
return false;
if(arr.length != pattern.length()) public boolean wordPatternMatch(String pattern, String str) {
return false; if(pattern.length()==0 && str.length()==0) char c = pattern.charAt(i);
return true; for(int k=j+1; k<=str.length(); k++){
HashMap<Character, String> map = new HashMap<Character, String>(); if(pattern.length()==0) String sub = str.substring(j, k);
for(int i=0; i<pattern.length(); i++){ return false; if(!map.containsKey(c) && !set.contains(sub)){
char c = pattern.charAt(i);
map.put(c, sub);
if(map.containsKey(c)){ HashMap<Character, String> map = new HashMap<Character, String>(); set.add(sub);
String value = map.get(c);
if(helper(pattern, str, i+1, k, map, set))
if(!value.equals(arr[i])){ return helper(pattern, str, 0, 0, map); return true;
return false; } map.remove(c);
}
set.remove(sub);
}else if (map.containsValue(arr[i])){ public boolean helper(String pattern, String str, int i, int j, HashMap<Character, String> map){ }else if(map.containsKey(c) && map.get(c).equals(sub)){
return false; if(i==pattern.length() && j==str.length()){ if(helper(pattern, str, i+1, k, map, set))
} return true; return true;
map.put(c, arr[i]); } }
}
}
if(i>=pattern.length() || j>=str.length())
return true; return false; return false;
}
}
char c = pattern.charAt(i);
for(int k=j+1; k<=str.length(); k++){ The time complexity then is f(n) = n*(n-1)*... *1=nn̂.
String sub = str.substring(j, k);
if(!map.containsKey(c) && !map.containsValue(sub)){
map.put(c, sub);
if(helper(pattern, str, i+1, k, map))
return true;
map.remove(c);
}else if(map.containsKey(c) && map.get(c).equals(sub)){
if(helper(pattern, str, i+1, k, map))
return true;
}
}

return false;
}

Since containsValue() method is used here, the time complexity is O(n). We can use another set to track the
value set which leads to time complexity of O(1):

454 | 568 455 | 568 Program Creek 456 | 568


238 Remove Invalid Parentheses

}else{
dfs(left.substring(1), right+String.valueOf(left.charAt(0)), countLeft, maxLeft);
}
}
237 Scramble String 238 Remove Invalid Parentheses }

Given two strings s1 and s2 of the same length, determine if s2 is a scrambled string of s1. Remove the minimum number of invalid parentheses in order to make the input string valid. Return all possible
results.
Note: The input string may contain letters other than the parentheses ( and ).
237.1 Java Solution Examples: "()())()" ->["()()()", "(())()"] "(a)())()" ->["(a)()()", "(a())()"] ")(" ->[""]

public boolean isScramble(String s1, String s2) {


if(s1.length()!=s2.length())
238.1 Java Solution
return false;
This problem can be solve by using DFS.
if(s1.length()==0 || s1.equals(s2))
public class Solution {
return true;
ArrayList<String> result = new ArrayList<String>();
int max=0;
char[] arr1 = s1.toCharArray();
char[] arr2 = s2.toCharArray();
public List<String> removeInvalidParentheses(String s) {
Arrays.sort(arr1);
if(s==null)
Arrays.sort(arr2);
return result;
if(!new String(arr1).equals(new String(arr2))){
return false;
dfs(s, "", 0, 0);
}
if(result.size()==0){
result.add("");
for(int i=1; i<s1.length(); i++){
}
String s11 = s1.substring(0, i);
String s12 = s1.substring(i, s1.length());
return result;
String s21 = s2.substring(0, i);
}
String s22 = s2.substring(i, s2.length());
String s23 = s2.substring(0, s2.length()-i);
public void dfs(String left, String right, int countLeft, int maxLeft){
String s24 = s2.substring(s2.length()-i, s2.length());
if(left.length()==0){
if(countLeft==0 && right.length()!=0){
if(isScramble(s11, s21) && isScramble(s12, s22))
if(maxLeft > max){
return true;
max = maxLeft;
if(isScramble(s11, s24) && isScramble(s12, s23))
}
return true;
}
if(maxLeft==max && !result.contains(right)){
result.add(right);
return false;
}
}
}

return;
}

if(left.charAt(0)==’(’){
dfs(left.substring(1), right+"(", countLeft+1, maxLeft+1);//keep (
dfs(left.substring(1), right, countLeft, maxLeft);//drop (
}else if(left.charAt(0)==’)’){
if(countLeft>0){
dfs(left.substring(1), right+")", countLeft-1, maxLeft);
}

dfs(left.substring(1), right, countLeft, maxLeft);

457 | 568 458 | 568 Program Creek 459 | 568


239 Shortest Palindrome

} else {
if ((result = scanFromCenter(s, i - 1, i - 1)) != null)
return result;
}
}
239 Shortest Palindrome 240 Lexicographical Numbers
return result;
}
Given a string S, you are allowed to convert it to a palindrome by adding characters in front of it. Find and return Given an integer n, return 1 - n in lexicographical order.
the shortest palindrome you can find by performing this transformation. private String scanFromCenter(String s, int l, int r) { For example, given 13, return: [1,10,11,12,13,2,3,4,5,6,7,8,9].
For example, given "aacecaaa", return "aaacecaaa"; given "abcd", return "dcbabcd". int i = 1; Please optimize your algorithm to use less time and space. The input size may be as large as 5,000,000.

//scan from center to both sides


239.1 Java Solution 1 for (; l - i >= 0; i++) { 240.1 Java Solution - DFS
if (s.charAt(l - i) != s.charAt(r + i))
break;
public String shortestPalindrome(String s) { } public List<Integer> lexicalOrder(int n) {
int i=0; int c=0;
int j=s.length()-1; //if not end at the beginning of s, return null int t=n;
if (l - i >= 0) while(t>0){
while(j>=0){ return null; c++;
if(s.charAt(i)==s.charAt(j)){ t=t/10;
i++; StringBuilder sb = new StringBuilder(s.substring(r + i)); }
} sb.reverse();
j--; ArrayList<Integer> result = new ArrayList<Integer>();
} return sb.append(s).toString(); char[] num = new char[c];
}
if(i==s.length()) helper(num, 0, n, result);
return s;
return result;
String suffix = s.substring(i); }
String prefix = new StringBuilder(suffix).reverse().toString();
String mid = shortestPalindrome(s.substring(0, i)); public void helper(char[] num, int i, int max, ArrayList<Integer> result){
return prefix+mid+suffix; if(i==num.length){
} int val = convert(num);
if(val <=max)
result.add(val);
return;
239.2 Java Solution 2 }

We can solve this problem by using one of the methods which is used to solve the longest palindrome substring if(i==0){
problem. for(char c=’1’; c<=’9’; c++){
Specifically, we can start from the center and scan two sides. If read the left boundary, then the shortest num[i]=c;
helper(num, i+1, max, result);
palindrome is identified.
}
public String shortestPalindrome(String s) { }else{
if (s == null || s.length() <= 1) num[i]=’a’;
return s; helper(num, num.length, max, result);

String result = null; for(char c=’0’; c<=’9’; c++){


num[i]=c;
int len = s.length(); helper(num, i+1, max, result);
int mid = len / 2; }
}
for (int i = mid; i >= 1; i--) {
if (s.charAt(i) == s.charAt(i - 1)) { }
if ((result = scanFromCenter(s, i - 1, i)) != null)
return result; private int convert(char[] arr){

460 | 568 Program Creek 461 | 568 462 | 568


240 Lexicographical Numbers

int result=0;
for(int i=0; i<arr.length; i++){
if(arr[i]>=’0’&&arr[i]<=’9’)
result = result*10+arr[i]-’0’;
else
break; 241 Combinations 242 Letter Combinations of a Phone Number
}
return result;
} Given two integers n and k, return all possible combinations of k numbers out of 1 ... n. Given a digit string, return all possible letter combinations that the number could represent. (Check out your
For example, if n = 4 and k = 2, a solution is: cellphone to see the mappings) Input:Digit string "23", Output: ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].

240.2 Java Solution 2 - Comparator [2,4], 242.1 Java Solution 1 - DFS


[3,4],
[2,3], This problem can be solves by a typical DFS algorithm. DFS problems are very similar and can be solved by using
public List<Integer> lexicalOrder(int n) { [1,2],
a simple recursion.
List<String> list = new ArrayList<>(); [1,3],
for(int i=1;i<=n;i++){ [1,4], public List<String> letterCombinations(String digits) {
list.add(String.valueOf(i)); ] HashMap<Character, char[]> dict = new HashMap<Character, char[]>();
} dict.put(’2’,new char[]{’a’,’b’,’c’});
dict.put(’3’,new char[]{’d’,’e’,’f’});
Collections.sort(list, new Comparator<String>(){ dict.put(’4’,new char[]{’g’,’h’,’i’});
public int compare(String a, String b){ 241.1 Java Solution dict.put(’5’,new char[]{’j’,’k’,’l’});
int i=0; dict.put(’6’,new char[]{’m’,’n’,’o’});
while(i<a.length()&&i<b.length()){ dict.put(’7’,new char[]{’p’,’q’,’r’,’s’});
if(a.charAt(i)!=b.charAt(i)){ public ArrayList<ArrayList<Integer>> combine(int n, int k) { dict.put(’8’,new char[]{’t’,’u’,’v’});
return a.charAt(i)-b.charAt(i); ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>(); dict.put(’9’,new char[]{’w’,’x’,’y’,’z’});
}
i++; if (n <= 0 || n < k) List<String> result = new ArrayList<String>();
} return result; if(digits==null||digits.length()==0){
return result;
if(i>=a.length()){ ArrayList<Integer> item = new ArrayList<Integer>(); }
return -1; dfs(n, k, 1, item, result); // because it need to begin from 1
} char[] arr = new char[digits.length()];
return result; helper(digits, 0, dict, result, arr);
return 1; }
} return result;
}); private void dfs(int n, int k, int start, ArrayList<Integer> item, }
ArrayList<ArrayList<Integer>> res) {
List<Integer> result = new ArrayList<>(); if (item.size() == k) { private void helper(String digits, int index, HashMap<Character, char[]> dict,
for(String s: list){ res.add(new ArrayList<Integer>(item)); List<String> result, char[] arr){
result.add(Integer.parseInt(s)); return; if(index==digits.length()){
} } result.add(new String(arr));
return;
return result; for (int i = start; i <= n; i++) { }
} item.add(i);
dfs(n, k, i + 1, item, res); char number = digits.charAt(index);
item.remove(item.size() - 1); char[] candidates = dict.get(number);
} for(int i=0; i<candidates.length; i++){
} arr[index]=candidates[i];
helper(digits, index+1, dict, result, arr);
}
}

Time complexity is O(kn̂), where k is the biggest number of letters a digit can map (k=4) and n is the length of
the digit string.

Program Creek 463 | 568 464 | 568 465 | 568


242 Letter Combinations of a Phone Number 243 Restore IP Addresses

242.2 Java Solution 2 - BFS if(i>1 && s.charAt(start)==’0’){


break;
}
public List<String> letterCombinations(String digits) {
HashMap<Character, String> map = new HashMap<>(); //make sure each number <= 255
map.put(’2’, "abc"); 243 Restore IP Addresses if(Integer.valueOf(sub)>255)
map.put(’3’, "def"); break;
map.put(’4’, "ghi");
map.put(’5’, "jkl"); Given a string containing only digits, restore it by returning all possible valid IP address combinations. t.add(sub);
map.put(’6’, "mno"); For example: given "25525511135",return ["255.255.11.135", "255.255.111.35"]. dfs(result, s, start+i, t);
map.put(’7’, "pqrs"); t.remove(t.size()-1);
map.put(’8’, "tuv"); }
map.put(’9’, "wxyz"); 243.1 Java Solution }

List<String> l = new ArrayList<>(); This is a typical search problem and it can be solved by using DFS.
if (digits == null || digits.length() == 0) {
return l; public List<String> restoreIpAddresses(String s) {
} ArrayList<ArrayList<String>> result = new ArrayList<ArrayList<String>>();
ArrayList<String> t = new ArrayList<String>();
l.add(""); dfs(result, s, 0, t);

for (int i = 0; i < digits.length(); i++) { ArrayList<String> finalResult = new ArrayList<String>();


ArrayList<String> temp = new ArrayList<>();
String option = map.get(digits.charAt(i)); for(ArrayList<String> l: result){
StringBuilder sb = new StringBuilder();
for (int j = 0; j < l.size(); j++) { for(String str: l){
for (int p = 0; p < option.length(); p++) { sb.append(str+".");
temp.add(new StringBuilder(l.get(j)).append(option.charAt(p)).toString()); }
} sb.setLength(sb.length() - 1);
} finalResult.add(sb.toString());
}
l.clear();
l.addAll(temp); return finalResult;
} }

return l; public void dfs(ArrayList<ArrayList<String>> result, String s, int start, ArrayList<String> t){
} //if already get 4 numbers, but s is not consumed, return
if(t.size()>=4 && start!=s.length())
return;

//make sure t’s size + remaining string’s length >=4


if((t.size()+s.length()-start+1)<4)
return;

//t’s size is 4 and no remaining part that is not consumed.


if(t.size()==4 && start==s.length()){
ArrayList<String> temp = new ArrayList<String>(t);
result.add(temp);
return;
}

for(int i=1; i<=3; i++){


//make sure the index is within the boundary
if(start+i>s.length())
break;

String sub = s.substring(start, start+i);


//handle case like 001. i.e., if length > 1 and first char is 0, ignore the case.

Program Creek 466 | 568 467 | 568 Program Creek 468 | 568
245 Subsets

single.add(S[i]);
temp.add(single);

result.addAll(temp);
}
244 Factor Combinations 245 Subsets
//add empty set
result.add(new ArrayList<Integer>());
Numbers can be regarded as product of its factors. For example, Given a set of distinct integers, S, return all possible subsets.
Note: 1) Elements in a subset must be in non-descending order. 2) The solution set must not contain duplicate return result;
8 = 2 x 2 x 2;
subsets. }
= 2 x 4.
For example, given S = [1,2,3], the method returns:
Write a function that takes an integer n and return all possible combinations of its factors. [
Note: You may assume that n is always positive. Factors should be greater than 1 and less than n. [3],
[1],
[2],
244.1 Java Solution [1,2,3],
[1,3],
[2,3],
public List<List<Integer>> getFactors(int n) { [1,2],
List<List<Integer>> result = new ArrayList<List<Integer>>(); []
List<Integer> list = new ArrayList<Integer>(); ]
helper(2, 1, n, result, list);
return result;
}

245.1 Thoughts
public void helper(int start, int product, int n, List<List<Integer>> result, List<Integer> curr){
if(start>n || product > n )
Given a set S of n distinct integers, there is a relation between Sn and Sn-1. The subset of Sn-1 is the union of
return ;
subset of Sn-1 and each element in Sn-1 + one more element. Therefore, a Java solution can be quickly formalized.
if(product==n) {
ArrayList<Integer> t = new ArrayList<Integer>(curr);
result.add(t);
245.2 Java Solution
return;
}
public ArrayList<ArrayList<Integer>> subsets(int[] S) {
if (S == null)
for(int i=start; i<n; i++){
return null;
if(i*product>n)
break;
Arrays.sort(S);

if(n%i==0){
ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();
curr.add(i);
helper(i, i*product, n, result, curr);
for (int i = 0; i < S.length; i++) {
curr.remove(curr.size()-1);
ArrayList<ArrayList<Integer>> temp = new ArrayList<ArrayList<Integer>>();
}
}
//get sets that are already in result
}
for (ArrayList<Integer> a : result) {
temp.add(new ArrayList<Integer>(a));
}

//add S[i] to existing sets


for (ArrayList<Integer> a : temp) {
a.add(S[i]);
}

//add S[i] only as a set


ArrayList<Integer> single = new ArrayList<Integer>();

469 | 568 470 | 568 Program Creek 471 | 568


246 Subsets II

if (i == num.length - 1 || num[i] != num[i + 1]) {


ArrayList<Integer> temp = new ArrayList<Integer>();
temp.add(num[i]);
prev.add(temp);
}
246 Subsets II 247 Coin Change
//add all set created in this iteration
for (ArrayList<Integer> temp : prev) {
Given a set of distinct integers, S, return all possible subsets. result.add(new ArrayList<Integer>(temp)); You are given coins of different denominations and a total amount of money amount. Write a function to compute
Note: Elements in a subset must be in non-descending order. The solution set must not contain duplicate } the fewest number of coins that you need to make up that amount. If that amount of money cannot be made up
subsets. For example, If S = [1,2,3], a solution is: } by any combination of the coins, return -1.

[ //add empty set


[3], result.add(new ArrayList<Integer>()); 247.1 Java Solution 1 - Dynamic Programming (Looking Backward)
[1],
[2], return result; Given an amount of 6 and coins [1,2,5], we can look backward in the dp array.
[1,2,3], }
[1,3],
[2,3],
Feed the method [1,2,3] the following will be result at each iteration.
[1,2],
[] [2]
] [2][2,2]
[2][2,2][1,2][1,2,2][1]
Get [] finally.

246.1 Thoughts
Comparing this problem with Subsets can help better understand the problem.

246.2 Java Solution

public ArrayList<ArrayList<Integer>> subsetsWithDup(int[] num) {


if (num == null)
return null;

Let dp[i] to be the minimum number of coins required to get the amount i.
Arrays.sort(num);
dp[i] = 1, if i==coin
otherwise, dp[i]=min(dp[i-coin]+1, dp[i]) if dp[i-coin] is reachable.
ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();
We initially set dp[i] to be MAX_VALUE.
ArrayList<ArrayList<Integer>> prev = new ArrayList<ArrayList<Integer>>();

for (int i = num.length-1; i >= 0; i--) {


public int coinChange(int[] coins, int amount) {
if(amount==0){
//get existing sets
return 0;
if (i == num.length - 1 || num[i] != num[i + 1] || prev.size() == 0) {
}
prev = new ArrayList<ArrayList<Integer>>();
for (int j = 0; j < result.size(); j++) {
int[] dp = new int[amount+1];
prev.add(new ArrayList<Integer>(result.get(j)));
}
Arrays.fill(dp, Integer.MAX_VALUE);
}
dp[0]=0;

//add current number to each element of the set


for(int i=1; i<=amount; i++){
for (ArrayList<Integer> temp : prev) {
for(int coin: coins){
temp.add(0, num[i]);
if(i==coin){
}
dp[i]=1;
}else if(i>coin){
//add each single number as a set, only if current element is different with previous
if(dp[i-coin]==Integer.MAX_VALUE){

472 | 568 Program Creek 473 | 568 474 | 568


247 Coin Change 247 Coin Change

continue; }
} }
dp[i]=Math.min(dp[i-coin]+1, dp[i]); }
}
} if(dp[amount]==Integer.MAX_VALUE){
} return -1; 248 Palindrome Partitioning
}
if(dp[amount]==Integer.MAX_VALUE){
return -1; return dp[amount]; 248.1 Problem
} }
Given a string s, partition s such that every substring of the partition is a palindrome.
return dp[amount]; Time and space are the same as Solution 1. Return all possible palindrome partitioning of s.
}
For example, given s = "aab", Return
Time complexity is O(amount * num_of_coins) and space complexity is O(amount). 247.3 Java Solution 3 - Breath First Search (BFS) [
["aa","b"],
Dynamic programming problems can often be solved by using BFS. ["a","a","b"]
247.2 Java Solution 2 - Dynamic Programming (Looking Forward) We can view this problem as going to a target position with steps that are allows in the array coins. We maintain ]
two queues: one of the amount so far and the other for the minimal steps. The time is too much because of the
contains method take n and total time is O(n3̂).

public int coinChange(int[] coins, int amount) { 248.2 Depth-first Search


if (amount == 0)
return 0;
public ArrayList<ArrayList<String>> partition(String s) {
LinkedList<Integer> amountQueue = new LinkedList<Integer>(); ArrayList<ArrayList<String>> result = new ArrayList<ArrayList<String>>();
LinkedList<Integer> stepQueue = new LinkedList<Integer>();
if (s == null || s.length() == 0) {
// to get 0, 0 step is required return result;
amountQueue.offer(0); }
stepQueue.offer(0);
ArrayList<String> partition = new ArrayList<String>();//track each possible partition
while (amountQueue.size() > 0) { addPalindrome(s, 0, partition, result);
Let dp[i] to be the minimum number of coins required to get the amount i. int temp = amountQueue.poll();
dp[i+coin] = min(dp[i+coin], dp[i]+1) if dp[i] is reachable. int step = stepQueue.poll(); return result;
dp[i+coin] = dp[i+coin] is dp[i] is not reachable. }
We initially set dp[i] to be MAX_VALUE. if (temp == amount)
return step; private void addPalindrome(String s, int start, ArrayList<String> partition,
Here is the Java code: ArrayList<ArrayList<String>> result) {
for (int coin : coins) { //stop condition
public int coinChange(int[] coins, int amount) { if (temp > amount) { if (start == s.length()) {
if(amount==0){ continue; ArrayList<String> temp = new ArrayList<String>(partition);
return 0; } else { result.add(temp);
} if (!amountQueue.contains(temp + coin)) { return;
amountQueue.offer(temp + coin); }
int[] dp = new int[amount+1]; stepQueue.offer(step + 1);
} for (int i = start + 1; i <= s.length(); i++) {
Arrays.fill(dp, Integer.MAX_VALUE); } String str = s.substring(start, i);
dp[0]=0; } if (isPalindrome(str)) {
} partition.add(str);
for(int i=0; i<=amount; i++){ addPalindrome(s, i, partition, result);
if(dp[i]==Integer.MAX_VALUE){ return -1; partition.remove(partition.size() - 1);
continue; } }
} }
}
for(int coin: coins){
if(i<=amount-coin){ //handle case when coin is Integer.MAX_VALUE private boolean isPalindrome(String str) {
dp[i+coin] = Math.min(dp[i]+1, dp[i+coin]); int left = 0;

Program Creek 475 | 568 Program Creek 476 | 568 477 | 568
248 Palindrome Partitioning

int right = str.length() - 1;

while (left < right) {


if (str.charAt(left) != str.charAt(right)) {
return false;
} 249 Palindrome Partitioning II 250 House Robber
left++;
right--; Given a string s, partition s such that every substring of the partition is a palindrome. Return the minimum You are a professional robber planning to rob houses along a street. Each house has a certain amount of money
} cuts needed for a palindrome partitioning of s. For example, given s = "aab", return 1 since the palindrome stashed, the only constraint stopping you from robbing each of them is that adjacent houses have security system
partitioning ["aa","b"] could be produced using 1 cut. connected and it will automatically contact the police if two adjacent houses were broken into on the same night.
return true; Given a list of non-negative integers representing the amount of money of each house, determine the maximum
} amount of money you can rob tonight without alerting the police.
249.1 Analysis
This problem is similar to Palindrome Partitioning. It can be efficiently solved by using dynamic programming. 250.1 Java Solution 1 - Dynamic Programming
248.3 Dynamic Programming Unlike "Palindrome Partitioning", we need to maintain two cache arrays, one tracks the partition position and
one tracks the number of minimum cut. The key is to find the relation dp[i] = Math.max(dp[i-1], dp[i-2]+nums[i]).
The dynamic programming approach is very similar to the problem of longest palindrome substring.
public int rob(int[] nums) {
public static List<String> palindromePartitioning(String s) { 249.2 Java Solution if(nums==null||nums.length==0)
return 0;
List<String> result = new ArrayList<String>();
public int minCut(String s) { if(nums.length==1)
if (s == null) int n = s.length(); return nums[0];
return result;
boolean dp[][] = new boolean[n][n]; int[] dp = new int[nums.length];
if (s.length() <= 1) { int cut[] = new int[n]; dp[0]=nums[0];
result.add(s); dp[1]=Math.max(nums[0], nums[1]);
return result; for (int j = 0; j < n; j++) {
} cut[j] = j; //set maximum # of cut for(int i=2; i<nums.length; i++){
for (int i = 0; i <= j; i++) { dp[i] = Math.max(dp[i-2]+nums[i], dp[i-1]);
int length = s.length(); if (s.charAt(i) == s.charAt(j) && (j - i <= 1 || dp[i+1][j-1])) { }
dp[i][j] = true;
int[][] table = new int[length][length]; return dp[nums.length-1];
// if need to cut, add 1 to the previous cut[i-1] }
// l is length, i is index of left boundary, j is index of right boundary if (i > 0){
for (int l = 1; l <= length; l++) { cut[j] = Math.min(cut[j], cut[i-1] + 1);
for (int i = 0; i <= length - l; i++) { }else{
int j = i + l - 1; // if [0...j] is palindrome, no need to cut 250.2 Java Solution 2
if (s.charAt(i) == s.charAt(j)) { cut[j] = 0;
if (l == 1 || l == 2) { } We can use two variables, even and odd, to track the maximum value so far as iterating the array. You can use
table[i][j] = 1; } the following example to walk through the code.
} else { }
table[i][j] = table[i + 1][j - 1]; } 50 1 1 50
}
if (table[i][j] == 1) { return cut[n-1];
result.add(s.substring(i, j + 1)); }
}
} else {
table[i][j] = 0;
}
}
}

return result;
}

Program Creek 478 | 568 479 | 568 480 | 568


250 House Robber

public int rob(int[] num) {


if(num==null || num.length == 0)
return 0;

int even = 0; 251 House Robber II 252 House Robber III


int odd = 0;

for (int i = 0; i < num.length; i++) { After robbing those houses on that street, the thief has found himself a new place for his thievery so that he will The houses form a binary tree. If the root is robbed, its left and right can not be robbed.
if (i % 2 == 0) { not get too much attention. This time, all houses at this place are arranged in a circle. That means the first house
even += num[i]; is the neighbor of the last one. Meanwhile, the security system for these houses remain the same as for those in
even = even > odd ? even : odd; the previous street. 252.1 Analysis
} else {
Given a list of non-negative integers representing the amount of money of each house, determine the maximum
odd += num[i]; Traverse down the tree recursively. We can use an array to keep 2 values: the maximum money when a root is
amount of money you can rob tonight without alerting the police.
odd = even > odd ? even : odd; selected and the maximum value when a root if NOT selected.
}
}
251.1 Analysis
252.2 Java Solution
return even > odd ? even : odd;
}
This is an extension of House Robber. There are two cases here 1) 1st element is included and last is not included
2) 1st is not included and last is included. Therefore, we can use the similar dynamic programming approach to public int rob(TreeNode root) {
scan the array twice and get the larger value. if(root == null)
return 0;
250.3 Java Solution 3 - Dynamic Programming with Memorization
251.2 Java Solution int[] result = helper(root);
return Math.max(result[0], result[1]);
public int rob(int[] nums) { }
if(nums.length==0){ public int rob(int[] nums) {
return 0; if(nums==null || nums.length==0)
public int[] helper(TreeNode root){
} return 0;
if(root == null){
int[] result = {0, 0};
int[] mem = new int[nums.length+1]; if(nums.length==1)
return result;
Arrays.fill(mem, -1); return nums[0];
}

mem[0] = 0; int max1 = robHelper(nums, 0, nums.length-2);


int[] result = new int[2];
int max2 = robHelper(nums, 1, nums.length-1);
int[] left = helper(root.left);
return helper(nums.length, mem, nums); int[] right = helper (root.right);
} return Math.max(max1, max2);
}
// result[0] is when root is selected, result[1] is when not.
private int helper(int size, int[] mem, int[] nums){ result[0] = root.val + left[1] + right[1];
if(size <1){ public int robHelper(int[] nums, int i, int j){
result[1] = Math.max(left[0], left[1]) + Math.max(right[0], right[1]);
return 0; if(i==j){
} return nums[i];
return result;
}
}
if(mem[size]!=-1){
return mem[size]; int[] dp = new int[nums.length];
} dp[i]=nums[i];
dp[i+1]=Math.max(nums[i+1], dp[i]);
//two cases
int firstSelected = helper(size-2, mem, nums) + nums[nums.length -size]; for(int k=i+2; k<=j; k++){
int firstUnselected = helper(size-1, mem, nums); dp[k]=Math.max(dp[k-1], dp[k-2]+nums[k]);
}
return mem[size] = Math.max(firstSelected, firstUnselected);
} return dp[j];
}

Program Creek 481 | 568 482 | 568 483 | 568


253 Jump Game

return true;
}

return false;
}
253 Jump Game 254 Jump Game II
Given an array of non-negative integers, you are initially positioned at the first index of the array. Each element Given an array of non-negative integers, you are initially positioned at the first index of the array. Each element
in the array represents your maximum jump length at that position. Determine if you are able to reach the last in the array represents your maximum jump length at that position.
index. For example: A = [2,3,1,1,4], return true. A = [3,2,1,0,4], return false. Your goal is to reach the last index in the minimum number of jumps.
For example, given array A = [2,3,1,1,4], the minimum number of jumps to reach the last index is 2. (Jump 1
step from index 0 to 1, then 3 steps to the last index.)
253.1 Analysis
We can track the maximum index that can be reached. The key to solve this problem is to find: 1) when the 254.1 Analysis
current position can not reach next position (return false) , and 2) when the maximum index can reach the end
(return true). This is an extension of Jump Game.
The largest index that can be reached is: i + A[i]. The solution is similar, but we also track the maximum steps of last jump.

254.2 Java Solution

public int jump(int[] nums) {


if (nums == null || nums.length == 0)
return 0;

int lastReach = 0;
int reach = 0;
int step = 0;

for (int i = 0; i <= reach && i < nums.length; i++) {


//when last jump can not read current i, increase the step by 1
if (i > lastReach) {
step++;
lastReach = reach;
253.2 Java Solution }
//update the maximal jump
reach = Math.max(reach, nums[i] + i);
public boolean canJump(int[] A) { }
if(A.length <= 1)
return true; if (reach < nums.length - 1)
return 0;
int max = A[0]; //max stands for the largest index that can be reached.
return step;
for(int i=0; i<A.length; i++){ }
//if not enough to go to next
if(max <= i && A[i] == 0)
return false;

//update max
if(i + A[i] > max){
max = i + A[i];
}

//max is enough to reach the end


if(max >= A.length-1)

484 | 568 Program Creek 485 | 568 486 | 568


255 Best Time to Buy and Sell Stock 256 Best Time to Buy and Sell Stock II 257 Best Time to Buy and Sell Stock III
Say you have an array for which the ith element is the price of a given stock on day i. Say you have an array for which the ith element is the price of a given stock on day i. Say you have an array for which the ith element is the price of a given stock on day i.
If you were only permitted to complete at most one transaction (ie, buy one and sell one share of the stock), Design an algorithm to find the maximum profit. You may complete as many transactions as you like (ie, buy Design an algorithm to find the maximum profit. You may complete at most two transactions.
design an algorithm to find the maximum profit. one and sell one share of the stock multiple times). However, you may not engage in multiple transactions at the Note: A transaction is a buy & a sell. You may not engage in multiple transactions at the same time (ie, you
same time (ie, you must sell the stock before you buy again). must sell the stock before you buy again).

255.1 Java Solution


256.1 Analysis 257.1 Analysis
Instead of keeping track of largest element in the array, we track the maximum profit so far.
This problem can be viewed as finding all ascending sequences. For example, given 5, 1, 2, 3, 4, buy at 1 & sell at Comparing to I and II, III limits the number of transactions to 2. This can be solve by "devide and conquer". We
public int maxProfit(int[] prices) {
4 is the same as buy at 1 &sell at 2 & buy at 2& sell at 3 & buy at 3 & sell at 4. use left[i] to track the maximum profit for transactions before i, and use right[i] to track the maximum profit for
if(prices==null||prices.length<=1)
We can scan the array once, and find all pairs of elements that are in ascending order. transactions after i. You can use the following example to understand the Java solution:
return 0;
Prices: 1 4 5 7 6 3 2 9
int min=prices[0]; // min so far
int result=0;
256.2 Java Solution left = [0, 3, 4, 6, 6, 6, 6, 8]
right= [8, 7, 7, 7, 7, 7, 7, 0]

for(int i=1; i<prices.length; i++){ public int maxProfit(int[] prices) { The maximum profit = 13
result = Math.max(result, prices[i]-min); int profit = 0;
min = Math.min(min, prices[i]); for(int i=1; i<prices.length; i++){
} int diff = prices[i]-prices[i-1]; 257.2 Java Solution
if(diff > 0){
return result; profit += diff;
} } public int maxProfit(int[] prices) {
} if (prices == null || prices.length < 2) {
return profit; return 0;
} }

//highest profit in 0 ... i


int[] left = new int[prices.length];
int[] right = new int[prices.length];

// DP from left to right


left[0] = 0;
int min = prices[0];
for (int i = 1; i < prices.length; i++) {
min = Math.min(min, prices[i]);
left[i] = Math.max(left[i - 1], prices[i] - min);
}

// DP from right to left


right[prices.length - 1] = 0;
int max = prices[prices.length - 1];
for (int i = prices.length - 2; i >= 0; i--) {
max = Math.max(max, prices[i]);
right[i] = Math.max(right[i + 1], max - prices[i]);
}

int profit = 0;
for (int i = 0; i < prices.length; i++) {
profit = Math.max(profit, left[i] + right[i]);

487 | 568 488 | 568 489 | 568


257 Best Time to Buy and Sell Stock III 258 Best Time to Buy and Sell Stock IV

} 258.4 Java Solution - 1D Dynamic Programming


return profit; The solution above can be simplified to be the following:
}
public int maxProfit(int k, int[] prices) {
258 Best Time to Buy and Sell Stock IV if (prices.length < 2 || k <= 0)
return 0;

//pass leetcode online judge (can be ignored)


258.1 Problem
if (k == 1000000000)
return 1648961;
Say you have an array for which the ith element is the price of a given stock on day i.Design an algorithm to find
the maximum profit. You may complete at most k transactions. int[] local = new int[k + 1];
Note: You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy int[] global = new int[k + 1];
again).
for (int i = 0; i < prices.length - 1; i++) {
int diff = prices[i + 1] - prices[i];
258.2 Analysis for (int j = k; j >= 1; j--) {
local[j] = Math.max(global[j - 1] + Math.max(diff, 0), local[j] + diff);
This is a generalized version of Best Time to Buy and Sell Stock III. If we can solve this problem, we can also use global[j] = Math.max(local[j], global[j]);
k=2 to solve III. }
The problem can be solve by using dynamic programming. The relation is: }

local[i][j] = max(global[i-1][j-1] + max(diff,0), local[i-1][j]+diff) return global[k];


global[i][j] = max(local[i][j], global[i-1][j]) }

We track two arrays - local and global. The local array tracks maximum profit of j transactions & the last
transaction is on ith day. The global array tracks the maximum profit of j transactions until ith day.

258.3 Java Solution - 2D Dynamic Programming

public int maxProfit(int k, int[] prices) {


int len = prices.length;

if (len < 2 || k <= 0)


return 0;

// ignore this line


if (k == 1000000000)
return 1648961;

int[][] local = new int[len][k + 1];


int[][] global = new int[len][k + 1];

for (int i = 1; i < len; i++) {


int diff = prices[i] - prices[i - 1];
for (int j = 1; j <= k; j++) {
local[i][j] = Math.max(
global[i - 1][j - 1] + Math.max(diff, 0),
local[i - 1][j] + diff);
global[i][j] = Math.max(global[i - 1][j], local[i][j]);
}
}

return global[prices.length - 1][k];


}

Program Creek 490 | 568 491 | 568 Program Creek 492 | 568
259 Dungeon Game 260 Decode Ways 261 Perfect Squares
Example: A message containing letters from A-Z is being encoded to numbers using the following mapping: Given a positive integer n, find the least number of perfect square numbers (for example, 1, 4, 9, 16, ...) which
’A’ ->1 ’B’ ->2 ... ’Z’ ->26 sum to n.
-2 (K) -3 3
Given an encoded message containing digits, determine the total number of ways to decode it. For example, given n = 12, return 3 because 12 = 4 + 4 + 4; given n = 13, return 2 because 13 = 4 + 9.
-5 -10 1
10 30 -5 (P)

260.1 Java Solution 261.1 Java Solution


This problem can be solve by using dynamic programming. It is similar to the problem of counting ways of This is a dp problem. The key is to find the relation which is dp[i] = min(dp[i], dp[i-square]+1). For example,
259.1 Java Solution climbing stairs. The relation is dp[n]=dp[n-1]+dp[n-2]. dp[5]=dp[4]+1=1+1=2.
This problem can be solved by using dynamic programming. We maintain a 2-D table. h[i][j] is the minimum public int numDecodings(String s) { public int numSquares(int n) {
health value before he enters (i,j). h[0][0] is the value of the answer. The left part is filling in numbers to the table. if(s==null || s.length()==0 || s.charAt(0)==’0’) int max = (int) Math.sqrt(n);
return 0;
public int calculateMinimumHP(int[][] dungeon) { if(s.length()==1) int[] dp = new int[n+1];
int m = dungeon.length; return 1; Arrays.fill(dp, Integer.MAX_VALUE);
int n = dungeon[0].length;
int[] dp = new int[s.length()]; for(int i=1; i<=n; i++){
//init dp table dp[0]=1; for(int j=1; j<=max; j++){
int[][] h = new int[m][n]; if(Integer.parseInt(s.substring(0,2))>26){ if(i==j*j){
if(s.charAt(1)!=’0’){ dp[i]=1;
h[m - 1][n - 1] = Math.max(1 - dungeon[m - 1][n - 1], 1); dp[1]=1; }else if(i>j*j){
}else{ dp[i]=Math.min(dp[i], dp[i-j*j] + 1);
//init last row dp[1]=0; }
for (int i = m - 2; i >= 0; i--) { } }
h[i][n - 1] = Math.max(h[i + 1][n - 1] - dungeon[i][n - 1], 1); }else{ }
} if(s.charAt(1)!=’0’){
dp[1]=2; return dp[n];
//init last column }else{ }
for (int j = n - 2; j >= 0; j--) { dp[1]=1;
h[m - 1][j] = Math.max(h[m - 1][j + 1] - dungeon[m - 1][j], 1); }
} }

//calculate dp table for(int i=2; i<s.length(); i++){


for (int i = m - 2; i >= 0; i--) { if(s.charAt(i)!=’0’){
for (int j = n - 2; j >= 0; j--) { dp[i]+=dp[i-1];
int down = Math.max(h[i + 1][j] - dungeon[i][j], 1); }
int right = Math.max(h[i][j + 1] - dungeon[i][j], 1);
h[i][j] = Math.min(right, down); int val = Integer.parseInt(s.substring(i-1, i+1));
} if(val<=26 && val >=10){
} dp[i]+=dp[i-2];
}
return h[0][0]; }
}
return dp[s.length()-1];
}

493 | 568 494 | 568 495 | 568


262 Word Break 262 Word Break

t[0] = true; //set first to be true, why? 262.4 The More Interesting Problem
//Because we need initial state
The dynamic solution can tell us whether the string can be broken to words, but can not tell us what words the
for(int i=0; i<s.length(); i++){ string is broken to. So how to get those words?
//should continue from match position Check out Word Break II.
262 Word Break if(!t[i])
continue;

Given a string s and a dictionary of words dict, determine if s can be segmented into a space-separated sequence of one for(String a: dict){
or more dictionary words. For example, given s = "leetcode", dict = ["leet", "code"]. Return true because "leetcode" int len = a.length();
can be segmented as "leet code". int end = i + len;
if(end > s.length())
continue;
262.1 Naive Approach
if(t[end]) continue;
This problem can be solve by using a naive approach, which is trivial. A discussion can always start from that
though. if(s.substring(i, end).equals(a)){
t[end] = true;
public class Solution { }
public boolean wordBreak(String s, Set<String> dict) { }
return wordBreakHelper(s, dict, 0); }
}
return t[s.length()];
public boolean wordBreakHelper(String s, Set<String> dict, int start){ }
if(start == s.length()) }
return true;
Time: O(string length * dict size).
for(String a: dict){
int len = a.length();
int end = start+len; 262.3 Java Solution 3 - Simple and Efficient
//end index should be <= string length In Solution 2, if the size of the dictionary is very large, the time is bad. Instead we can solve the problem in O(n2̂)
if(end > s.length())
time (n is the length of the string).
continue;
public boolean wordBreak(String s, Set<String> wordDict) {
if(s.substring(start, start+len).equals(a)) int[] pos = new int[s.length()+1];
if(wordBreakHelper(s, dict, start+len))
return true; Arrays.fill(pos, -1);
}
pos[0]=0;
return false;
} for(int i=0; i<s.length(); i++){
} if(pos[i]!=-1){
for(int j=i+1; j<=s.length(); j++){
Time is O(n2̂) and exceeds the time limit. String sub = s.substring(i, j);
if(wordDict.contains(sub)){
pos[j]=i;
262.2 Dynamic Programming }
}
The key to solve this problem by using dynamic programming approach: }
}
• Define an array t[] such that t[i]==true =>0-(i-1) can be segmented using dictionary
• Initial state t[0] == true return pos[s.length()]!=-1;
}

public class Solution {


public boolean wordBreak(String s, Set<String> dict) {
boolean[] t = new boolean[s.length()+1];

496 | 568 Program Creek 497 | 568 Program Creek 498 | 568
263 Word Break II 263 Word Break II

for(String word:dict){ ArrayList<String> list = new ArrayList<String>();


int len = word.length(); list.add(sub);
int end = i+len; pos[j]=list;
if(end > s.length()) }else{
continue; pos[j].add(sub);
263 Word Break II }
if(s.substring(i,end).equals(word)){
if(dp[end] == null){ }
Given a string s and a dictionary of words dict, add spaces in s to construct a sentence where each word is a valid dp[end] = new ArrayList<String>(); }
dictionary word. Return all such possible sentences. For example, given s = "catsanddog", dict = ["cat", "cats", } }
"and", "sand", "dog"], the solution is ["cats and dog", "cat sand dog"]. dp[end].add(word); }
}
} if(pos[s.length()]==null){
263.1 Java Solution 1 - Dynamic Programming } return new ArrayList<String>();
}else{
This problem is very similar to Word Break. Instead of using a boolean array to track the matched positions, we List<String> result = new LinkedList<String>(); ArrayList<String> result = new ArrayList<String>();
need to track the actual matched words. Then we can use depth first search to get all the possible paths, i.e., the if(dp[s.length()] == null) dfs(pos, result, "", s.length());
list of strings. return result; return result;
The following diagram shows the structure of the tracking array. }
ArrayList<String> temp = new ArrayList<String>(); }
dfs(dp, s.length(), result, temp);
public void dfs(ArrayList<String> [] pos, ArrayList<String> result, String curr, int i){
return result; if(i==0){
} result.add(curr.trim());
return;
public static void dfs(List<String> dp[],int end,List<String> result, ArrayList<String> tmp){ }
if(end <= 0){
String path = tmp.get(tmp.size()-1); for(String s: pos[i]){
for(int i=tmp.size()-2; i>=0; i--){ String combined = s + " "+ curr;
path += " " + tmp.get(i) ; dfs(pos, result, combined, i-s.length());
} }
}
result.add(path);
return; This problem is also useful for solving real problems. Assuming you want to analyze the domain names of
} the top 10k websites. We can use this solution to break the main part of the domain into words and then get a
sense of what kinds of websites are popular. I did this a long time ago and found some interesting results. For
for(String str : dp[end]){
example, the most frequent words include "news", "tube", "porn", "etc".
tmp.add(str);
dfs(dp, end-str.length(), result, tmp);
tmp.remove(tmp.size()-1);
}
}

263.2 Java Solution 2 - Simplified

public List<String> wordBreak(String s, Set<String> wordDict) {


public static List<String> wordBreak(String s, Set<String> dict) { ArrayList<String> [] pos = new ArrayList[s.length()+1];
//create an array of ArrayList<String> pos[0]=new ArrayList<String>();
List<String> dp[] = new ArrayList[s.length()+1];
dp[0] = new ArrayList<String>(); for(int i=0; i<s.length(); i++){
if(pos[i]!=null){
for(int i=0; i<s.length(); i++){ for(int j=i+1; j<=s.length(); j++){
if( dp[i] == null ) String sub = s.substring(i,j);
continue; if(wordDict.contains(sub)){
if(pos[j]==null){

499 | 568 Program Creek 500 | 568 Program Creek 501 | 568
265 Maximal Square

return result*result;
}

264 Minimum Window Subsequence 265 Maximal Square


Given strings S and T, find the minimum (contiguous) substring W of S, so that T is a subsequence of W. Given a 2D binary matrix filled with 0’s and 1’s, find the largest square containing all 1’s and return its area.
If there is no such window in S that covers all characters in T, return the empty string "". If there are multiple For example, given the following matrix:
such minimum-length windows, return the one with the left-most starting index.
1101
Example 1:
1101
Input: S = "abcdebdde", T = "bde" Output: "bcde" Explanation: "bcde" is the answer because it occurs before
1111
"bdde" which has the same length. "deb" is not a smaller window because the elements of T in the window must
occur in order.
Return 4.

264.1 Java Solution 1 - Two pointers 265.1 Analysis


In a brute-force way, this problem can be solved by using two pointers which iterate over characters of the two
This problem can be solved by dynamic programming. The changing condition is: t[i][j] = min(t[i][j-1], t[i-1][j],
strings respectively.
t[i-1][j-1]) + 1. It means the square formed before this point.
public String minWindow(String S, String T) {
int start=0;
String result = ""; 265.2 Java Solution

while(start<S.length()){
public int maximalSquare(char[][] matrix) {
int j=0;
if(matrix==null||matrix.length==0){
return 0;
for(int i=start; i<S.length(); i++){
}
if(S.charAt(i)==T.charAt(j)&&j==0){
start=i;
int result=0;
}
int[][] dp = new int[matrix.length][matrix[0].length];

if(S.charAt(i)==T.charAt(j)){
for(int i=0; i<matrix.length; i++){
j++;
dp[i][0]=matrix[i][0]-’0’;
}
result=Math.max(result, dp[i][0]);
}
if(j==T.length()){
if(result.equals("")||(i-start+1)<result.length()){
for(int j=0; j<matrix[0].length; j++){
result = S.substring(start, i+1);
dp[0][j]=matrix[0][j]-’0’;
}
result=Math.max(result, dp[0][j]);
start=start+1;
}
break;
}
for(int i=1; i<matrix.length; i++){
for(int j=1; j<matrix[0].length; j++){
if(i==S.length()-1){
if(matrix[i][j]==’1’){
return result;
int min = Math.min(dp[i-1][j], dp[i][j-1]);
}
min = Math.min(min, dp[i-1][j-1]);
}
dp[i][j]=min+1;
}

result = Math.max(result, min+1);


return result;
}else{
}
dp[i][j]=0;
}
}
}

502 | 568 503 | 568 Program Creek 504 | 568


266 Minimum Path Sum

for(int i=1; i<n; i++){


dp[0][i] = dp[0][i-1] + grid[0][i];
}

// initialize left column


266 Minimum Path Sum for(int j=1; j<m; j++){ 267 Unique Paths
dp[j][0] = dp[j-1][0] + grid[j][0];
}
Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which minimizes A robot is located at the top-left corner of a m x n grid. It can only move either down or right at any point in
the sum of all numbers along its path. // fill up the dp table time. The robot is trying to reach the bottom-right corner of the grid.
for(int i=1; i<m; i++){ How many possible unique paths are there?
for(int j=1; j<n; j++){
266.1 Java Solution 1: Depth-First Search if(dp[i-1][j] > dp[i][j-1]){
dp[i][j] = dp[i][j-1] + grid[i][j]; 267.1 Java Solution 1 - DFS
A native solution would be depth-first search. It’s time is too expensive and fails the online judgement. }else{
dp[i][j] = dp[i-1][j] + grid[i][j]; A depth-first search solution is pretty straight-forward. However, the time of this solution is too expensive, and
public int minPathSum(int[][] grid) { } it didn’t pass the online judge.
return dfs(0,0,grid); }
} } public int uniquePaths(int m, int n) {
return dfs(0,0,m,n);
public int dfs(int i, int j, int[][] grid){ return dp[m-1][n-1]; }
if(i==grid.length-1 && j==grid[0].length-1){ }
return grid[i][j]; public int dfs(int i, int j, int m, int n){
} if(i==m-1 && j==n-1){
return 1;
if(i<grid.length-1 && j<grid[0].length-1){ }
int r1 = grid[i][j] + dfs(i+1, j, grid);
int r2 = grid[i][j] + dfs(i, j+1, grid); if(i<m-1 && j<n-1){
return Math.min(r1,r2); return dfs(i+1,j,m,n) + dfs(i,j+1,m,n);
} }

if(i<grid.length-1){ if(i<m-1){
return grid[i][j] + dfs(i+1, j, grid); return dfs(i+1,j,m,n);
} }

if(j<grid[0].length-1){ if(j<n-1){
return grid[i][j] + dfs(i, j+1, grid); return dfs(i,j+1,m,n);
} }

return 0; return 0;
} }

266.2 Java Solution 2: Dynamic Programming 267.2 Java Solution 2 - Dynamic Programming

public int minPathSum(int[][] grid) { public int uniquePaths(int m, int n) {


if(grid == null || grid.length==0) if(m==0 || n==0) return 0;
return 0; if(m==1 || n==1) return 1;

int m = grid.length; int[][] dp = new int[m][n];


int n = grid[0].length;
//left column
int[][] dp = new int[m][n]; for(int i=0; i<m; i++){
dp[0][0] = grid[0][0]; dp[i][0] = 1;
}
// initialize top row

505 | 568 Program Creek 506 | 568 507 | 568


267 Unique Paths 268 Unique Paths II

//top row for(int i=1; i<m; i++){


for(int j=0; j<n; j++){ for(int j=1; j<n; j++){
dp[0][j] = 1; if(obstacleGrid[i][j]==1){
} dp[i][j]=0;
}else{
//fill up the dp table 268 Unique Paths II dp[i][j]=dp[i-1][j]+dp[i][j-1];
for(int i=1; i<m; i++){ }
for(int j=1; j<n; j++){
dp[i][j] = dp[i-1][j] + dp[i][j-1]; Follow up for "Unique Paths": }
} Now consider if some obstacles are added to the grids. How many unique paths would there be? }
} An obstacle and empty space is marked as 1 and 0 respectively in the grid. For example, there is one obstacle
in the middle of a 3x3 grid as illustrated below, return dp[m-1][n-1];
return dp[m-1][n-1]; }
} [
[0,0,0],
[0,1,0],
[0,0,0]
267.3 Java Solution 3 - Dynamic Programming with Memorization ]

the total number of unique paths is 2.


public int uniquePaths(int m, int n) {
int[][] mem = new int[m][n];
268.1 Java Solution
//init with -1 value
for(int i=0; i<m; i++){
for(int j=0; j<n; j++){ public int uniquePathsWithObstacles(int[][] obstacleGrid) {
mem[i][j]=-1; if(obstacleGrid==null||obstacleGrid.length==0)
} return 0;
}
int m = obstacleGrid.length;
return helper(mem, m-1, n-1); int n = obstacleGrid[0].length;
}
if(obstacleGrid[0][0]==1||obstacleGrid[m-1][n-1]==1)
private int helper(int[][] mem, int m, int n){ return 0;
//edge has only one path
if(m==0||n==0){
mem[m][n]=1; int[][] dp = new int[m][n];
return 1; dp[0][0]=1;
}
//left column
if(mem[m][n]!=-1){ for(int i=1; i<m; i++){
return mem[m][n]; if(obstacleGrid[i][0]==1){
} dp[i][0] = 0;
}else{
mem[m][n] = helper(mem, m, n-1) + helper(mem, m-1, n); dp[i][0] = dp[i-1][0];
}
return mem[m][n]; }
}
//top row
for(int i=1; i<n; i++){
if(obstacleGrid[0][i]==1){
dp[0][i] = 0;
}else{
dp[0][i] = dp[0][i-1];
}
}

//fill up cells inside

Program Creek 508 | 568 509 | 568 Program Creek 510 | 568
269 Paint House

return result;
}

269 Paint House 270 Paint House II


There are a row of n houses, each house can be painted with one of the three colors: red, blue or green. The cost There are a row of n houses, each house can be painted with one of the k colors. The cost of painting each house
of painting each house with a certain color is different. You have to paint all the houses such that no two adjacent with a certain color is different. You have to paint all the houses such that no two adjacent houses have the same
houses have the same color. color.
The cost of painting each house with a certain color is represented by a n x 3 cost matrix. For example, The cost of painting each house with a certain color is represented by a n x k cost matrix. For example,
costs[0][0] is the cost of painting house 0 with color red; costs[1][2] is the cost of painting house 1 with color costs[0][0] is the cost of painting house 0 with color 0; costs[1][2] is the cost of painting house 1 with color 2, and
green, and so on... Find the minimum cost to paint all houses. so on... Find the minimum cost to paint all houses.

269.1 Java Solution 270.1 Java Solution


A typical DP problem.
public int minCostII(int[][] costs) {
public int minCost(int[][] costs) { if(costs==null || costs.length==0)
if(costs==null||costs.length==0) return 0;
return 0;
int preMin=0;
for(int i=1; i<costs.length; i++){ int preSecond=0;
costs[i][0] += Math.min(costs[i-1][1], costs[i-1][2]); int preIndex=-1;
costs[i][1] += Math.min(costs[i-1][0], costs[i-1][2]);
costs[i][2] += Math.min(costs[i-1][0], costs[i-1][1]); for(int i=0; i<costs.length; i++){
} int currMin=Integer.MAX_VALUE;
int currSecond = Integer.MAX_VALUE;
int m = costs.length-1; int currIndex = 0;
return Math.min(Math.min(costs[m][0], costs[m][1]), costs[m][2]);
} for(int j=0; j<costs[0].length; j++){
if(preIndex==j){
Or a different way of writing the code without original array value changed. costs[i][j] += preSecond;
}else{
public int minCost(int[][] costs) { costs[i][j] += preMin;
if(costs==null||costs.length==0){ }
return 0;
} if(currMin>costs[i][j]){
currSecond = currMin;
int[][] matrix = new int[3][costs.length]; currMin=costs[i][j];
currIndex = j;
for(int j=0; j<costs.length; j++){ } else if(currSecond>costs[i][j] ){
if(j==0){ currSecond = costs[i][j];
matrix[0][j]=costs[j][0]; }
matrix[1][j]=costs[j][1]; }
matrix[2][j]=costs[j][2];
}else{ preMin=currMin;
matrix[0][j]=Math.min(matrix[1][j-1], matrix[2][j-1])+costs[j][0]; preSecond=currSecond;
matrix[1][j]=Math.min(matrix[0][j-1], matrix[2][j-1])+costs[j][1]; preIndex =currIndex;
matrix[2][j]=Math.min(matrix[0][j-1], matrix[1][j-1])+costs[j][2]; }
}
} int result = Integer.MAX_VALUE;
for(int j=0; j<costs[0].length; j++){
int result = Math.min(matrix[0][costs.length-1], matrix[1][costs.length-1]); if(result>costs[costs.length-1][j]){
result = Math.min(result, matrix[2][costs.length-1]); result = costs[costs.length-1][j];
}

511 | 568 Program Creek 512 | 568 513 | 568


270 Paint House II 271 Edit Distance in Java

} Initial condition: dp[i][0] = i, dp[0][j] = j


return result;
}
271.2 Java Solution 1 - Iteration
271 Edit Distance in Java After the analysis above, the code is just a representation of it.

public static int minDistance(String word1, String word2) {


From Wiki: int len1 = word1.length();
In computer science, edit distance is a way of quantifying how dissimilar two strings (e.g., words) are to one another int len2 = word2.length();
by counting the minimum number of operations required to transform one string into the other.
There are three operations permitted on a word: replace, delete, insert. For example, the edit distance between // len1+1, len2+1, because finally return dp[len1][len2]
"a" and "b" is 1, the edit distance between "abc" and "def" is 3. This post analyzes how to calculate edit distance int[][] dp = new int[len1 + 1][len2 + 1];
by using dynamic programming.
for (int i = 0; i <= len1; i++) {
dp[i][0] = i;
}
271.1 Key Analysis
for (int j = 0; j <= len2; j++) {
Let dp[i][j] stands for the edit distance between two strings with length i and j, i.e., word1[0,...,i-1] and word2[0,...,j-
dp[0][j] = j;
1]. There is a relation between dp[i][j] and dp[i-1][j-1]. Let’s say we transform from one string to another. The
}
first string has length i and it’s last character is "x"; the second string has length j and its last character is "y". The
following diagram shows the relation. //iterate though, and check last char
for (int i = 0; i < len1; i++) {
char c1 = word1.charAt(i);
for (int j = 0; j < len2; j++) {
char c2 = word2.charAt(j);

//if last two chars equal


if (c1 == c2) {
//update dp value for +1 length
dp[i + 1][j + 1] = dp[i][j];
} else {
int replace = dp[i][j] + 1;
int insert = dp[i][j + 1] + 1;
int delete = dp[i + 1][j] + 1;

int min = replace > insert ? insert : replace;


min = delete > min ? min : delete;
dp[i + 1][j + 1] = min;
}
}
}

return dp[len1][len2];
}

271.3 Java Solution 2 - Recursion

• if x == y, then dp[i][j] == dp[i-1][j-1] We can write the solution in recursion.

• if x != y, and we insert y for word1, then dp[i][j] = dp[i][j-1] + 1 public int minDistance(String word1, String word2) {
int m=word1.length();
• if x != y, and we delete x for word1, then dp[i][j] = dp[i-1][j] + 1
int n=word2.length();
• if x != y, and we replace x with y for word1, then dp[i][j] = dp[i-1][j-1] + 1 int[][] mem = new int[m][n];
• When x!=y, dp[i][j] is the min of the three situations. for(int[] arr: mem){

Program Creek 514 | 568 515 | 568 Program Creek 516 | 568
271 Edit Distance in Java 272 Distinct Subsequences Total

Arrays.fill(arr, -1); HashMap<Character, ArrayList<Integer>> map = new HashMap<Character, ArrayList<Integer>>();


}
return calDistance(word1, word2, mem, m-1, n-1); for (int i = 0; i < T.length(); i++) {
} if (map.containsKey(T.charAt(i))) {
map.get(T.charAt(i)).add(i);
private int calDistance(String word1, String word2, int[][] mem, int i, int j){ 272 Distinct Subsequences Total } else {
if(i<0){ ArrayList<Integer> temp = new ArrayList<Integer>();
return j+1; temp.add(i);
}else if(j<0){ Given a string S and a string T, count the number of distinct subsequences of T in S. map.put(T.charAt(i), temp);
return i+1; 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).
if(mem[i][j]!=-1){ Here is an example: S = "rabbbit", T = "rabbit" int[] result = new int[T.length() + 1];
return mem[i][j]; Return 3. result[0] = 1;
}
for (int i = 0; i < S.length(); i++) {
if(word1.charAt(i)==word2.charAt(j)){ 272.1 Analysis char c = S.charAt(i);
mem[i][j]=calDistance(word1, word2, mem, i-1, j-1);
}else{ The problem itself is very difficult to understand. It can be stated like this: Give a sequence S and T, how many if (map.containsKey(c)) {
int prevMin = Math.min(calDistance(word1, word2, mem, i, j-1), calDistance(word1, word2, mem, i-1, ArrayList<Integer> temp = map.get(c);
distinct sub sequences from S equals to T? How do you define "distinct" subsequence? Clearly, the ’distinct’ here
j)); int[] old = new int[temp.size()];
mean different operation combination, not the final string of subsequence. Otherwise, the result is always 0 or 1.
prevMin = Math.min(prevMin, calDistance(word1, word2, mem, i-1, j-1));
– from Jason’s comment
mem[i][j]=1+prevMin; for (int j = 0; j < temp.size(); j++)
}
When you see string problem that is about subsequence or matching, dynamic programming method should old[j] = result[temp.get(j)];
come to mind naturally. The key is to find the initial and changing condition.
return mem[i][j]; // the relation
} for (int j = 0; j < temp.size(); j++)
272.2 Java Solution 1 result[temp.get(j) + 1] = result[temp.get(j) + 1] + old[j];
}
Let W(i, j) stand for the number of subsequences of S(0, i) equals to T(0, j). If S.charAt(i) == T.charAt(j), W(i, j) = }
W(i-1, j-1) + W(i-1,j); Otherwise, W(i, j) = W(i-1,j).
return result[T.length()];
public int numDistincts(String S, String T) { }
int[][] table = new int[S.length() + 1][T.length() + 1];

for (int i = 0; i < S.length(); i++)


table[i][0] = 1;

for (int i = 1; i <= S.length(); i++) {


for (int j = 1; j <= T.length(); j++) {
if (S.charAt(i - 1) == T.charAt(j - 1)) {
table[i][j] += table[i - 1][j] + table[i - 1][j - 1];
} else {
table[i][j] += table[i - 1][j];
}
}
}

return table[S.length()][T.length()];
}

272.3 Java Solution 2


Do NOT write something like this, even it can also pass the online judge.

public int numDistinct(String S, String T) {

Program Creek 517 | 568 518 | 568 Program Creek 519 | 568
273 Longest Palindromic Substring

From the table, we can clearly see that the longest string is in cell table[1][5].

273.2 A Simple Algorithm


273 Longest Palindromic Substring We can scan to both sides for each character. Time O(n2̂), Space O(1) 274 Longest Common Subsequence
public String longestPalindrome(String s) {
Finding the longest palindromic substring is a classic problem of coding interview. This post summarizes 3 if (s.isEmpty()) { The longest common subsequence (LCS) problem is the problem of finding the longest subsequence common to
different solutions for this problem. return null; all sequences in a set of sequences (often just two sequences).
}

273.1 Dynamic Programming if (s.length() == 1) { 274.1 Analysis


return s;
Let s be the input string, i and j are two indices of the string. Define a 2-dimension array "table" and let table[i][j] }
denote whether a substring from i to j is palindrome.
Changing condition: String longest = s.substring(0, 1);
for (int i = 0; i < s.length(); i++) {
table[i+1][j-1] == 1 && s.charAt(i) == s.charAt(j) // get longest palindrome with center of i
=> String tmp = helper(s, i, i);
table[i][j] == 1 if (tmp.length() > longest.length()) {
longest = tmp;
Time O(n2̂) Space O(n2̂) }

public String longestPalindrome(String s) { // get longest palindrome with center of i, i+1


if(s==null || s.length()<=1) tmp = helper(s, i, i + 1);
return s; if (tmp.length() > longest.length()) {
longest = tmp;
int len = s.length(); }
int maxLen = 1; }
boolean [][] dp = new boolean[len][len];
return longest;
String longest = null; }
for(int l=0; l<s.length(); l++){
for(int i=0; i<len-l; i++){ // Given a center, either one letter or two letter,
int j = i+l; // Find longest palindrome
if(s.charAt(i)==s.charAt(j) && (j-i<=2||dp[i+1][j-1])){ public String helper(String s, int begin, int end) {
dp[i][j]=true; while (begin >= 0 && end <= s.length() - 1 && s.charAt(begin) == s.charAt(end)) {
begin--; 274.2 Java Solution
if(j-i+1>maxLen){ end++;
maxLen = j-i+1; }
longest = s.substring(i, j+1); return s.substring(begin + 1, end); public static int getLongestCommonSubsequence(String a, String b){
} } int m = a.length();
} int n = b.length();
} int[][] dp = new int[m+1][n+1];
}
273.3 Manacher’s Algorithm for(int i=0; i<=m; i++){
return longest; for(int j=0; j<=n; j++){
} Manacher’s algorithm is much more complicated to figure out, even though it will bring benefit of time complex- if(i==0 || j==0){
dp[i][j]=0;
ity of O(n). Since it is not typical, there is no need to waste time on that.
For example, if the input string is "dabcba", the final matrix would be the following: }else if(a.charAt(i-1)==b.charAt(j-1)){
dp[i][j] = 1 + dp[i-1][j-1];
1 0 0 0 0 0 }else{
0 1 0 0 0 1 dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]);
0 0 1 0 1 0 }
0 0 0 1 0 0 }
0 0 0 0 1 0 }
0 0 0 0 0 1

520 | 568 Program Creek 521 | 568 522 | 568


274 Longest Common Subsequence 275 Longest Common Substring

return dp[m][n]; int m = a.length();


} int n = b.length();

int max = 0;

275 Longest Common Substring int[][] dp = new int[m][n];

for(int i=0; i<m; i++){


In computer science, the longest common substring problem is to find the longest string that is a substring of two for(int j=0; j<n; j++){
or more strings. if(a.charAt(i) == b.charAt(j)){
if(i==0 || j==0){
dp[i][j]=1;
275.1 Analysis }else{
dp[i][j] = dp[i-1][j-1]+1;
Given two strings a and b, let dp[i][j] be the length of the common substring ending at a[i] and b[j]. }

if(max < dp[i][j])


max = dp[i][j];
}

}
}

return max;
}

This is a similar problem like longest common subsequence. The difference of the solution is that for this
problem when a[i]!=b[j], dp[i][j] are all zeros by default. However, in the longest common subsequence problem,
dp[i][j] values are carried from the previous values, i.e., dp[i-1][j] and dp[i][j-1].

The dp table looks like the following given a="abc" and b="abcd".

275.2 Java Solution

public static int getLongestCommonSubstring(String a, String b){

Program Creek 523 | 568 524 | 568 Program Creek 525 | 568
276 LRU Cache 276 LRU Cache

class LRUCache { //set a node to be head


HashMap<Integer, Node> map = null; private void setHead(Node t){
int cap; if(head!=null){
Node head = null; head.prev = t;
276 LRU Cache Node tail = null; }

public LRUCache(int capacity) { t.next = head;


Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following this.map = new HashMap<>(); t.prev = null;
operations: get and set. this.cap = capacity; head = t;
get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1. }
set(key, value) - Set or insert the value if the key is not already present. When the cache reached its capacity, it if(tail==null){
should invalidate the least recently used item before inserting a new item. public int get(int key) { tail = head;
if(!map.containsKey(key)){ }
return -1; }
276.1 Analysis } }

Node t = map.get(key);
The key to solve this problem is using a double linked list which enables us to quickly move nodes.
remove(t);
setHead(t);

return t.value;
}

public void put(int key, int value) {


if(map.containsKey(key)){
Node t = map.get(key);
t.value = value;

remove(t);
setHead(t);
}else{
if(map.size()>=cap){
map.remove(tail.key);
remove(tail);
}
The LRU cache is a hash table of keys and double linked nodes. The hash table makes the time of get() to be
O(1). The list of double linked nodes make the nodes adding/removal operations O(1).
Node t = new Node(key, value);
setHead(t);
map.put(key, t);
276.2 Java Solution }
}
Define a double linked list.
//remove a node
class Node{
private void remove(Node t){
int key;
if(t.prev!=null){
int value;
t.prev.next = t.next;
Node prev;
}else{
Node next;
head = t.next;
}
public Node(int key, int value){
this.key=key;
if(t.next!=null){
this.value=value;
t.next.prev = t.prev;
}
}else{
}
tail = t.prev;
}
By analyzing the get and put, we can summarize there are 3 basic operations: 1) remove(Node t), 2) set-
}
Head(Node t), and 3) HashMap put()/remove(). We only need to define the first two operations.

526 | 568 Program Creek 527 | 568 Program Creek 528 | 568
277 Insert Delete GetRandom O(1)

/** Get a random element from the set. */


public int getRandom() {
if(valueMap.size()==0){
277 Insert Delete GetRandom O(1) return -1; 278 Insert Delete GetRandom O(1) Duplicates
}

Design a data structure that supports all following operations in O(1) time.
allowed
if(valueMap.size()==1){
insert(val): Inserts an item val to the set if not already present. remove(val): Removes an item val from the set if return idxMap.get(0);
present. getRandom: Returns a random element from current set of elements. Each element must have the same } Design a data structure that supports all following operations in average O(1) time.
probability of being returned. Note: Duplicate elements are allowed.
Random r = new Random();
int idx = r.nextInt(valueMap.size()); insert(val): Inserts an item val to the collection.
277.1 Java Solution remove(val): Removes an item val from the collection if present.
return idxMap.get(idx); getRandom(): Returns a random element from current collection of elements.
We can use two hashmaps to solve this problem. One uses value as keys and the other uses index as the keys. } The probability of each element being returned is linearly related to the number of same value the
} collection contains.
class RandomizedSet {
HashMap<Integer, Integer> valueMap;
HashMap<Integer, Integer> idxMap;
278.1 Java Solution
/** Initialize your data structure here. */
public RandomizedSet() { This problem is similar to Insert Delete GetRandom O(1). We can use two maps. One tracks the index of the
valueMap = new HashMap<>(); element, so that we can quickly insert and remove. The other maps tracks the order of each inserted element, so
idxMap = new HashMap<>(); that we can randomly access any element in time O(1).
}
public class RandomizedCollection {
/** Inserts a value to the set. Returns true if the set did not already contain the specified HashMap<Integer, HashSet<Integer>> map1;
element. */ HashMap<Integer, Integer> map2;
public boolean insert(int val) { Random r;
if(valueMap.containsKey(val)){
return false; /** Initialize your data structure here. */
} public RandomizedCollection() {
map1 = new HashMap<Integer, HashSet<Integer>>();
valueMap.put(val, valueMap.size()); map2 = new HashMap<Integer, Integer>();
idxMap.put(idxMap.size(), val); r = new Random();
}
return true;
} /** Inserts a value to the collection. Returns true if the collection did not already contain the
specified element. */
/** Removes a value from the set. Returns true if the set contained the specified element. */ public boolean insert(int val) {
public boolean remove(int val) { //add to map2
if(valueMap.containsKey(val)){ int size2 = map2.size();
int idx = valueMap.get(val); map2.put(size2+1, val);
valueMap.remove(val);
idxMap.remove(idx); if(map1.containsKey(val)){
map1.get(val).add(size2+1);
Integer tailElem = idxMap.get(idxMap.size()); return false;
if(tailElem!=null){ }else{
idxMap.put(idx,tailElem); HashSet<Integer> set = new HashSet<Integer>();
valueMap.put(tailElem, idx); set.add(size2+1);
} map1.put(val, set);
return true;
return true; }
} }

return false;

529 | 568 Program Creek 530 | 568 531 | 568


278 Insert Delete GetRandom O(1) Duplicates allowed 279 Design a Data Structure with Insert, Delete and GetMostFrequent of O(1)

/** Removes a value from the collection. Returns true if the collection contained the specified
element. */ if(n.next!=null){
public boolean remove(int val) { n.next.set.add(val); // next + 1
if(map1.containsKey(val)){ map.put(val, n.next);
HashSet<Integer> set = map1.get(val); }else{
int toRemove = set.iterator().next(); 279 Design a Data Structure with Insert, Delete Node t = new Node(n.value+1);
t.set.add(val);
and GetMostFrequent of O(1) n.next = t;
//remove from set of map1 t.prev = n;
set.remove(toRemove); map.put(val, t);
Design a data structure that allows O(1) time complexity to insert, delete and get most frequent element. }
if(set.size()==0){
map1.remove(val); //update head
} 279.1 Analysis if(head.next!=null)
head = head.next;
if(toRemove == map2.size()){ At first, a hash map seems to be good for insertion and deletion. But how to make getMostFrequent O(1)? Regular }else{
map2.remove(toRemove); sorting algorithm takes nlogn, so we can not use that. As a result we can use a linked list to track the maximum if(tail==null||head==null){
return true; frequency. Node n = new Node(1);
} n.set.add(val);
map.put(val, n);
int size2 = map2.size();
279.2 Java Solution
int key = map2.get(size2); head = n;
tail = n;
HashSet<Integer> setChange = map1.get(key); import java.util.*; return;
setChange.remove(size2); }
setChange.add(toRemove); class Node {
int value; if(tail.value>1){
Node prev; Node n = new Node(1);
Node next; n.set.add(val);
map2.remove(size2); HashSet<Integer> set; map.put(val, n);
map2.remove(toRemove); tail.prev = n;
public Node(int v){ n.next = tail;
map2.put(toRemove, key); value = v; tail = n;
set = new HashSet<Integer>(); }else{
return true; } tail.set.add(val);
} map.put(val, tail);
public String toString(){ }
return false; return value + ":" + set.toString();
} } }
}
/** Get a random element from the collection. */
public int getRandom() { public class FrequentCollection { }
if(map1.size()==0)
return -1; HashMap<Integer, Node> map; /**
Node head, tail; * Removes a value from the collection.
if(map2.size()==1){ */
return map2.get(1); /** Initialize your data structure here. */ public void remove(int val) {
} public FrequentCollection() { Node n = map.get(val);
map = new HashMap<Integer, Node>(); n.set.remove(val);
return map2.get(r.nextInt(map2.size())+1); // nextInt() returns a random number in [0, n). }
} if(n.value==1){
} /** map.remove(val);
* Inserts a value to the collection. }else{
*/ n.prev.set.add(val);
public void insert(int val) { map.put(val, n.prev);
if(map.containsKey(val)){ }
Node n = map.get(val);
n.set.remove(val);

Program Creek 532 | 568 533 | 568 Program Creek 534 | 568
279 Design a Data Structure with Insert, Delete and GetMostFrequent of O(1)

while(head!=null && head.set.size()==0){


head = head.prev;
}

} 280 Design Phone Directory 281 Design Twitter


/** Get the most frequent element from the collection. */
public int getMostFrequent() { Design a Phone Directory which supports the following operations: Design a simplified version of Twitter where users can post tweets, follow/unfollow another user and is able to
if(head==null) get: Provide a number which is not assigned to anyone. check: Check if a number is available or not. release: see the 10 most recent tweets in the user’s news feed. Your design should support the following methods:
return -1; Recycle or release a number. postTweet(userId, tweetId): Compose a new tweet. getNewsFeed(userId): Retrieve the 10 most recent tweet ids
else in the user’s news feed. Each item in the news feed must be posted by users who the user followed or by the
return head.set.iterator().next(); user herself. Tweets must be ordered from most recent to least recent. follow(followerId, followeeId): Follower
} 280.1 Java Solution 1 follows a followee. unfollow(followerId, followeeId): Follower unfollows a followee.

public static void main(String[] args) {


// TODO Auto-generated method stub public class PhoneDirectory {
int max;
281.1 Java Solution
FrequentCollection fc = new FrequentCollection();
fc.insert(1); HashSet<Integer> set;
fc.insert(2); LinkedList<Integer> queue; class Wrapper{
fc.insert(3); ArrayList<Integer> list;
fc.insert(2); /** Initialize your data structure here int index;
fc.insert(3); @param maxNumbers - The maximum numbers that can be stored in the phone directory. */
fc.insert(3); public PhoneDirectory(int maxNumbers) { public Wrapper(ArrayList<Integer> list, int index){
fc.insert(2); set = new HashSet<Integer>(); this.list=list;
fc.insert(2); queue = new LinkedList<Integer>(); this.index=index;
for(int i=0; i<maxNumbers; i++){ }
System.out.println(fc.getMostFrequent()); queue.offer(i); }
fc.remove(2); }
fc.remove(2); max=maxNumbers-1; public class Twitter {
System.out.println(fc.getMostFrequent()); } HashMap<Integer, HashSet<Integer>> userMap;//user and followees
HashMap<Integer, ArrayList<Integer>> tweetMap;//user and tweets
} /** Provide a number which is not assigned to anyone. HashMap<Integer, Integer> orderMap; //tweet and order
} @return - Return an available number. Return -1 if none is available. */ int order; //global order counter
public int get() {
if(queue.isEmpty()) /** Initialize your data structure here. */
In the implementation above, we only add nodes to the list. We can also delete nodes that does not hold any
return -1; public Twitter() {
elements.
userMap = new HashMap<Integer, HashSet<Integer>>();
int e = queue.poll(); tweetMap = new HashMap<Integer, ArrayList<Integer>>();
set.add(e); orderMap = new HashMap<Integer, Integer>();
return e; }
}
/** Compose a new tweet. */
/** Check if a number is available or not. */ public void postTweet(int userId, int tweetId) {
public boolean check(int number) { ArrayList<Integer> list = tweetMap.get(userId);
return !set.contains(number) && number<=max; if(list==null){
} list = new ArrayList<Integer>();
tweetMap.put(userId, list);
/** Recycle or release a number. */ }
public void release(int number) { list.add(tweetId);
if(set.contains(number)){ orderMap.put(tweetId, order++);
set.remove(number); follow(userId, userId);//follow himself
queue.offer(number); }
}
} /** Retrieve the 10 most recent tweet ids in the user’s news feed. Each item in the news feed must be
} posted by users who the user followed or by the user herself. Tweets must be ordered from most
recent to least recent. */
public List<Integer> getNewsFeed(int userId) {

Program Creek 535 | 568 536 | 568 537 | 568


281 Design Twitter 281 Design Twitter

HashSet<Integer> set = userMap.get(userId); }


if(set==null) }
return new ArrayList<Integer>();

ArrayList<ArrayList<Integer>> lists = new ArrayList<ArrayList<Integer>>();


282 Single Number
//get all users’ tweets
for(int uid: set){
if(tweetMap.get(uid)!=null && tweetMap.get(uid).size()>0) The problem:
lists.add(tweetMap.get(uid)); Given an array of integers, every element appears twice except for one. Find that single one.
}

ArrayList<Integer> result = new ArrayList<Integer>(); 282.1 Java Solution 1


PriorityQueue<Wrapper> queue = new PriorityQueue<Wrapper>(new Comparator<Wrapper>(){ The key to solve this problem is bit manipulation. XOR will return 1 only on two different bits. So if two numbers
public int compare(Wrapper a, Wrapper b){ are the same, XOR will return 0. Finally only one number left.
return orderMap.get(b.list.get(b.index))-orderMap.get(a.list.get(a.index));
} public int singleNumber(int[] A) {
}); int x = 0;
for (int a : A) {
for(ArrayList<Integer> list: lists){ x = x ^ a;
queue.offer(new Wrapper(list, list.size()-1)); }
} return x;
}
while(!queue.isEmpty() && result.size()<10){
Wrapper top = queue.poll();
result.add(top.list.get(top.index));
282.2 Java Solution 2
top.index--;

if(top.index>=0) public int singleNumber(int[] A) {


queue.offer(top); HashSet<Integer> set = new HashSet<Integer>();
} for (int n : A) {
if (!set.add(n))
return result; set.remove(n);
} }
Iterator<Integer> it = set.iterator();
/** Follower follows a followee. If the operation is invalid, it should be a no-op. */ return it.next();
public void follow(int followerId, int followeeId) { }
HashSet<Integer> set = userMap.get(followerId);
if(set==null){ The question now is do you know any other ways to do this?
set = new HashSet<Integer>();
userMap.put(followerId, set);
}
set.add(followeeId);
}

/** Follower unfollows a followee. If the operation is invalid, it should be a no-op. */


public void unfollow(int followerId, int followeeId) {
if(followerId==followeeId)
return ;

HashSet<Integer> set = userMap.get(followerId);


if(set==null){
return;
}

set.remove(followeeId);

Program Creek 538 | 568 Program Creek 539 | 568 540 | 568
284 Twitter Codility Problem Max Binary Gap

}
pre = curr;
}

return len;
283 Single Number II 284 Twitter Codility Problem Max Binary Gap }

Time is O(log(n)).
Problem: Get maximum binary Gap.
283.1 Problem
For example, 9’s binary form is 1001, the gap is 2.
Given an array of integers, every element appears three times except for one. Find that single one.
284.1 Java Solution 1
283.2 Java Solution
An integer x & 1 will get the last digit of the integer.
This problem is similar to Single Number. public static int getGap(int N) {
int max = 0;
public int singleNumber(int[] A) {
int count = -1;
int ones = 0, twos = 0, threes = 0;
int r = 0;
for (int i = 0; i < A.length; i++) {
twos |= ones & A[i];
while (N > 0) {
ones ^= A[i];
// get right most bit & shift right
threes = ones & twos;
r = N & 1;
ones &= ~threes;
N = N >> 1;
twos &= ~threes;
}
if (0 == r && count >= 0) {
return ones;
count++;
}
}

if (1 == r) {
max = count > max ? count : max;
count = 0;
}
}

return max;
}

Time is O(n).

284.2 Java Solution 2

public static int getGap(int N) {


int pre = -1;
int len = 0;

while (N > 0) {
int k = N & -N;

int curr = (int) Math.log(k);

N = N & (N - 1);

if (pre != -1 && Math.abs(curr - pre) > len) {


len = Math.abs(curr - pre) + 1;

541 | 568 542 | 568 Program Creek 543 | 568


285 Number of 1 Bits 286 Reverse Bits 287 Repeated DNA Sequences

285.1 Problem 286.1 Problem 287.1 Problem


Write a function that takes an unsigned integer and returns the number of ’1’ bits it has (also known as the Reverse bits of a given 32 bits unsigned integer. All DNA is composed of a series of nucleotides abbreviated as A, C, G, and T, for example: "ACGAATTCCG".
Hamming weight). For example, given input 43261596 (represented in binary as 00000010100101000001111010011100), return 964176192 When studying DNA, it is sometimes useful to identify repeated sequences within the DNA.
For example, the 32-bit integer ’11’ has binary representation 00000000000000000000000000001011, so the func- (represented in binary as 00111001011110000010100101000000). Write a function to find all the 10-letter-long sequences (substrings) that occur more than once in a DNA
tion should return 3. Follow up: If this function is called many times, how would you optimize it? molecule.
Related problem: Reverse Integer For example, given s = "AAAAACCCCCAAAAACCCCCCAAAAAGGGTTT", return: ["AAAAACCCCC",
"CCCCCAAAAA"].
285.2 Java Solution
286.2 Java Solution
287.2 Java Solution
public int hammingWeight(int n) {
int count = 0; public int reverseBits(int n) {
The key to solve this problem is that each of the 4 nucleotides can be stored in 2 bits. So the 10-letter-long
for(int i=1; i<33; i++){ for (int i = 0; i < 16; i++) {
sequence can be converted to 20-bits-long integer. The following is a Java solution. You may use an example to
if(getBit(n, i) == true){ n = swapBits(n, i, 32 - i - 1);
count++;
manually execute the program and see how it works.
}
}
public List<String> findRepeatedDnaSequences(String s) {
} return n;
List<String> result = new ArrayList<>();
return count; }
if(s==null||s.length()<10){
}
return result;
public int swapBits(int n, int i, int j) {
}
public boolean getBit(int n, int i){ int a = (n >> i) & 1;
return (n & (1 << i)) != 0; int b = (n >> j) & 1;
HashMap<Character, Integer> dict = new HashMap<>();
}
dict.put(’A’, 0);
if ((a ^ b) != 0) {
dict.put(’C’, 1);
return n ^= (1 << i) | (1 << j);
dict.put(’G’, 2);
}
dict.put(’T’, 3);

return n;
int hash=0;
}
int mask = (1<<20) -1;

HashSet<Integer> added = new HashSet<>();


HashSet<Integer> temp = new HashSet<>();

for(int i=0; i<s.length(); i++){


hash = (hash<<2) + dict.get(s.charAt(i));

if(i>=9){
hash&=mask;
if(temp.contains(hash) && !added.contains(hash)){
result.add(s.substring(i-9, i+1));
added.add(hash);
}

temp.add(hash);
}
}

return result;

544 | 568 545 | 568 546 | 568


287 Repeated DNA Sequences

288 Bitwise AND of Numbers Range 289 Sum of Two Integers


Calculate the sum of two integers a and b, but you are not allowed to use the operator + and -.
288.1 Given a range [m, n] where 0 <= m <= n <= 2147483647, return
Example: Given a = 1 and b = 2, return 3.
the bitwise AND of all numbers in this range, inclusive. For
example, given the range [5, 7], you should return 4. Java 289.1 Java Solution
Solution
Given two numbers a and b, a&b returns the number formed by ’1’ bits on a and b. When it is left shifted by 1
The key to solve this problem is bitwise AND consecutive numbers. You can use the following example to walk bit, it is the carry.
through the code. For example, given a=101 and b=111 (in binary), the a&b=101. a&b «1 = 1010.
ab̂ is the number formed by different bits of a and b. a&b=10.
8 4 2 1
--------------- public int getSum(int a, int b) {
5 | 0 1 0 1
6 | 0 1 1 0 while(b!=0){
7 | 0 1 1 1 int c = a&b;
a=a^b;
b=c<<1;
public int rangeBitwiseAnd(int m, int n) { }
while (n > m) {
n = n & n - 1; return a;
} }
return m & n;
}

Program Creek 547 | 568 548 | 568 549 | 568


290 Counting Bits

290 Counting Bits 291 Maximum Product of Word Lengths


Given a non negative integer number num. For every numbers i in the range 0 ≤ i ≤ num calculate the number Given a string array words, find the maximum value of length(word[i]) * length(word[j]) where the two words do
of 1’s in their binary representation and return them as an array. not share common letters. You may assume that each word will contain only lower case letters. If no such two
Example: words exist, return 0.
For num = 5 you should return [0,1,1,2,1,2].

291.1 Java Solution


290.1 Naive Solution
public int maxProduct(String[] words) {
We can simply count bits for each number like the following:
if(words==null || words.length==0)
public int[] countBits(int num) { return 0;
int[] result = new int[num+1];
int[] arr = new int[words.length];
for(int i=0; i<=num; i++){ for(int i=0; i<words.length; i++){
result[i] = countEach(i); for(int j=0; j<words[i].length(); j++){
} char c = words[i].charAt(j);
arr[i] |= (1<< (c-’a’));
return result; }
} }

public int countEach(int num){ int result = 0;


int result = 0; public int[] countBits(int num) {
int[] result = new int[num+1]; for(int i=0; i<words.length; i++){
while(num!=0){ for(int j=i+1; j<words.length; j++){
if(num%2==1){ int p = 1; //p tracks the index for number x if((arr[i] & arr[j]) == 0){
result++; int pow = 1; result = Math.max(result, words[i].length()*words[j].length());
} for(int i=1; i<=num; i++){ }
num = num/2; if(i==pow){ }
} result[i] = 1; }
pow <<= 1;
return result; p = 1; return result;
} }else{ }
result[i] = result[p]+1;
p++;
}
290.2 Improved Solution
}
For number 2(10), 4(100), 8(1000), 16(10000), ..., the number of 1’s is 1. Any other number can be converted to be
2m̂ + x. For example, 9=8+1, 10=8+2. The number of 1’s for any other number is 1 + # of 1’s in x. return result;
}

550 | 568 Program Creek 551 | 568 552 | 568


292 Gray Code 293 UTF8 Validation 294 Course Schedule
The gray code is a binary numeral system where two successive values differ in only one bit. A character in UTF8 can be from 1 to 4 bytes long, subjected to the following rules: There are a total of n courses you have to take, labeled from 0 to n - 1. Some courses may have prerequisites,
Given a non-negative integer n representing the total number of bits in the code, print the sequence of gray For 1-byte character, the first bit is a 0, followed by its unicode code. For n-bytes character, the first n-bits are all for example to take course 0 you have to first take course 1, which is expressed as a pair: [0,1]. Given the total
code. A gray code sequence must begin with 0. one’s, the n+1 bit is 0, followed by n-1 bytes with most significant 2 bits being 10. This is how the UTF-8 encoding number of courses and a list of prerequisite pairs, is it possible for you to finish all courses?
For example, given n = 2, return [0,1,3,2]. Its gray code sequence is: would work: For example, given 2 and [[1,0]], there are a total of 2 courses to take. To take course 1 you should have finished
course 0. So it is possible.
00 - 0 Char. number range | UTF-8 octet sequence
For another example, given 2 and [[1,0],[0,1]], there are a total of 2 courses to take. To take course 1 you should
01 - 1 (hexadecimal) | (binary)
have finished course 0, and to take course 0 you should also have finished course 1. So it is impossible.
11 - 3 --------------------+---------------------------------------------
10 - 2 0000 0000-0000 007F | 0xxxxxxx
0000 0080-0000 07FF | 110xxxxx 10xxxxxx
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
294.1 Analysis
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
This problem can be converted to finding if a graph contains a cycle.
292.1 Java Solution
Given an array of integers representing the data, return whether it is a valid utf-8 encoding.
public List<Integer> grayCode(int n) { 294.2 Java Solution 1 - BFS
if(n==0){ 293.1 Java Solution
List<Integer> result = new ArrayList<Integer>(); This solution uses breath-first search and it is easy to understand.
result.add(0);
public boolean canFinish(int numCourses, int[][] prerequisites) {
return result; public boolean validUtf8(int[] data) {
if(prerequisites == null){
} int i=0;
throw new IllegalArgumentException("illegal prerequisites array");
int count=0;
}
List<Integer> result = grayCode(n-1); while(i<data.length){
int numToAdd = 1<<(n-1); int v = data[i];
int len = prerequisites.length;
if(count==0){
for(int i=result.size()-1; i>=0; i--){ //iterate from last to first if((v&240)==240 && (v&248)==240){
if(numCourses == 0 || len == 0){
result.add(numToAdd+result.get(i)); count=3;
return true;
} }else if(((v&224)==224) && (v&240)==224){
}
count=2;
return result; }else if((v&192)==192 && (v&224)==192){
// counter for number of prerequisites
} count=1;
int[] pCounter = new int[numCourses];
}else if((v|127)==127){
for(int i=0; i<len; i++){
count=0;
pCounter[prerequisites[i][0]]++;
}else{
}
return false;
}
//store courses that have no prerequisites
}else{
LinkedList<Integer> queue = new LinkedList<Integer>();
if((v&128)==128 && (v&192)==128){
for(int i=0; i<numCourses; i++){
count--;
if(pCounter[i]==0){
}else{
queue.add(i);
return false;
}
}
}
}

// number of courses that have no prerequisites


i++;
int numNoPre = queue.size();
}

while(!queue.isEmpty()){
return count==0;
int top = queue.remove();
}
for(int i=0; i<len; i++){
// if a course’s prerequisite can be satisfied by a course in queue

553 | 568 554 | 568 555 | 568


294 Course Schedule 294 Course Schedule

if(prerequisites[i][1]==top){ visit[i]=-1;
pCounter[prerequisites[i][0]]--; if(map.containsKey(i)){
if(pCounter[prerequisites[i][0]]==0){ for(int j: map.get(i)){
numNoPre++; if(!canFinishDFS(map, visit, j))
queue.add(prerequisites[i][0]); return false;
} } 295 Course Schedule II
} }
}
} visit[i]=1; This is an extension of Course Schedule. This time a valid sequence of courses is required as output.

return numNoPre == numCourses; return true;


} } 295.1 Analysis

Topological Sort Video from Coursera. If we use the BFS solution of Course Schedule, a valid sequence can easily be recorded.

294.3 Java Solution 2 - DFS


295.2 Java Solution
public boolean canFinish(int numCourses, int[][] prerequisites) {
if(prerequisites == null){ public int[] findOrder(int numCourses, int[][] prerequisites) {
throw new IllegalArgumentException("illegal prerequisites array"); if(prerequisites == null){
} throw new IllegalArgumentException("illegal prerequisites array");
}
int len = prerequisites.length;
int len = prerequisites.length;
if(numCourses == 0 || len == 0){
return true; //if there is no prerequisites, return a sequence of courses
} if(len == 0){
int[] res = new int[numCourses];
//track visited courses for(int m=0; m<numCourses; m++){
int[] visit = new int[numCourses]; res[m]=m;
}
// use the map to store what courses depend on a course return res;
HashMap<Integer,ArrayList<Integer>> map = new HashMap<Integer,ArrayList<Integer>>(); }
for(int[] a: prerequisites){
if(map.containsKey(a[1])){ //records the number of prerequisites each course (0,...,numCourses-1) requires
map.get(a[1]).add(a[0]); int[] pCounter = new int[numCourses];
}else{ for(int i=0; i<len; i++){
ArrayList<Integer> l = new ArrayList<Integer>(); pCounter[prerequisites[i][0]]++;
l.add(a[0]); }
map.put(a[1], l);
} //stores courses that have no prerequisites
} LinkedList<Integer> queue = new LinkedList<Integer>();
for(int i=0; i<numCourses; i++){
for(int i=0; i<numCourses; i++){ if(pCounter[i]==0){
if(!canFinishDFS(map, visit, i)) queue.add(i);
return false; }
} }

return true; int numNoPre = queue.size();


}
//initialize result
private boolean canFinishDFS(HashMap<Integer,ArrayList<Integer>> map, int[] visit, int i){ int[] result = new int[numCourses];
if(visit[i]==-1) int j=0;
return false;
if(visit[i]==1) while(!queue.isEmpty()){
return true; int c = queue.remove();
result[j++]=c;

Program Creek 556 | 568 Program Creek 557 | 568 558 | 568
295 Course Schedule II 296 Minimum Height Trees

if(leaves.size()==0){
for(int i=0; i<len; i++){ return result;
if(prerequisites[i][1]==c){ }
pCounter[prerequisites[i][0]]--;
if(pCounter[prerequisites[i][0]]==0){ while(n>2){
queue.add(prerequisites[i][0]); 296 Minimum Height Trees n = n-leaves.size();
numNoPre++;
} LinkedList<Integer> newLeaves = new LinkedList<Integer>();
} For a undirected graph with tree characteristics, we can choose any node as the root. The result graph is then
a rooted tree. Among all possible rooted trees, those with minimum height are called minimum height trees for(int l: leaves){
} (MHTs). Given such a graph, write a function to find all the MHTs and return a list of their root labels. int neighbor = graph.get(l).iterator().next();
} The graph contains n nodes which are labeled from 0 to n - 1. You will be given the number n and a list of graph.get(neighbor).remove(l);
undirected edges (each edge is a pair of labels). if(graph.get(neighbor).size()==1){
//return result You can assume that no duplicate edges will appear in edges. Since all edges are undirected, [0, 1] is the same newLeaves.add(neighbor);
if(numNoPre==numCourses){ as [1, 0] and thus will not appear together in edges. }
return result; }
Example 1:
}else{
return new int[0]; Given n = 4, edges = [[1, 0], [1, 2], [1, 3]] leaves = newLeaves;
} }
} 0
| return leaves;
1 }
/ \
2 3
return [1]

296.1 Java Solution

public List<Integer> findMinHeightTrees(int n, int[][] edges) {


List<Integer> result = new ArrayList<Integer>();
if(n==0){
return result;
}
if(n==1){
result.add(0);
return result;
}

ArrayList<HashSet<Integer>> graph = new ArrayList<HashSet<Integer>>();


for(int i=0; i<n; i++){
graph.add(new HashSet<Integer>());
}

for(int[] edge: edges){


graph.get(edge[0]).add(edge[1]);
graph.get(edge[1]).add(edge[0]);
}

LinkedList<Integer> leaves = new LinkedList<Integer>();


for(int i=0; i<n; i++){
if(graph.get(i).size()==1){
leaves.offer(i);
}
}

Program Creek 559 | 568 560 | 568 Program Creek 561 | 568
297 Graph Valid Tree

return true;
}

297 Graph Valid Tree 298 Clone Graph


297.3 Java Solution 2 - BFS
Given n nodes labeled from 0 to n - 1 and a list of undirected edges (each edge is a pair of nodes), check if these Clone an undirected graph. Each node in the graph contains a label and a list of its neighbors.
edges form a valid tree. public boolean validTree(int n, int[][] edges) {
ArrayList<ArrayList<Integer>> list = new ArrayList<>();
for(int i=0; i<n; i++){ 298.1 Java Solution 1
297.1 Analysis list.add(new ArrayList<>());
} In this solution,
This problem can be converted to finding the cycle from a graph. It can be solved by using DFS (Recursion) or
BFS (Queue). //build the graph • a queue is used to do breath first traversal,
for(int[] edge: edges){ • and a map is used to store the visited nodes. It is the map between original node and copied node.
int a = edge[0];
297.2 Java Solution 1 - DFS int b = edge[1]; It would be helpful if you draw a diagram and visualize the problem.

list.get(a).add(b);
public boolean validTree(int n, int[][] edges) { list.get(b).add(a);
HashMap<Integer, ArrayList<Integer>> map = new HashMap<Integer, ArrayList<Integer>>(); }
for(int i=0; i<n; i++){
ArrayList<Integer> list = new ArrayList<Integer>(); //use queue to traverse the graph
map.put(i, list); HashSet<Integer> visited = new HashSet<>();
} LinkedList<Integer> q = new LinkedList<>();
q.offer(0);
for(int[] edge: edges){
map.get(edge[0]).add(edge[1]); while(!q.isEmpty()){
map.get(edge[1]).add(edge[0]); int head = q.poll();
}
if(visited.contains(head)){
boolean[] visited = new boolean[n]; return false;
}
if(!helper(0, -1, map, visited))
return false; visited.add(head);

for(boolean b: visited){ ArrayList<Integer> vList = list.get(head);


if(!b) for(int v: vList){
return false; if(!visited.contains(v)){
} q.offer(v);
}
return true; }
} }

public boolean helper(int curr, int parent, if(visited.size()<n){


HashMap<Integer, ArrayList<Integer>> map, boolean[] visited){ return false;
if(visited[curr]) }
return false;
return true;
visited[curr] = true; }

for(int i: map.get(curr)){
if(i!=parent && !helper(i, curr, map, visited)){ /**
return false; * Definition for undirected graph.
} * class UndirectedGraphNode {
} * int label;

562 | 568 Program Creek 563 | 568 564 | 568


298 Clone Graph 298 Clone Graph

* ArrayList<UndirectedGraphNode> neighbors; if(!map.containsKey(n))


* UndirectedGraphNode(int x) { label = x; neighbors = new ArrayList<UndirectedGraphNode>(); } queue.offer(n);
* }; }
*/ }
public class Solution {
public UndirectedGraphNode cloneGraph(UndirectedGraphNode node) { queue.offer(node); 299 Reconstruct Itinerary
if(node == null) HashSet<UndirectedGraphNode> set = new HashSet<UndirectedGraphNode>();
return null; set.add(node);
Given a list of airline tickets represented by pairs of departure and arrival airports [from, to], reconstruct the
LinkedList<UndirectedGraphNode> queue = new LinkedList<UndirectedGraphNode>(); while(!queue.isEmpty()){ itinerary in order. All of the tickets belong to a man who departs from JFK. Thus, the itinerary must begin with
HashMap<UndirectedGraphNode, UndirectedGraphNode> map = UndirectedGraphNode top = queue.poll(); JFK.
new HashMap<UndirectedGraphNode,UndirectedGraphNode>(); for(UndirectedGraphNode n: top.neighbors){
if(!set.contains(n)){
UndirectedGraphNode newHead = new UndirectedGraphNode(node.label); queue.offer(n); 299.1 Analysis
set.add(n);
queue.add(node); } This is an application of Hierholzer’s algorithm to find a Eulerian path.
map.put(node, newHead); map.get(top).neighbors.add(map.get(n)); PriorityQueue should be used instead of TreeSet, because there are duplicate entries.
}
while(!queue.isEmpty()){ }
UndirectedGraphNode curr = queue.pop(); 299.2 Java Solution
ArrayList<UndirectedGraphNode> currNeighbors = curr.neighbors; return map.get(node);
}
for(UndirectedGraphNode aNeighbor: currNeighbors){ public class Solution{
if(!map.containsKey(aNeighbor)){ HashMap<String, PriorityQueue<String>> map = new HashMap<String, PriorityQueue<String>>();
UndirectedGraphNode copy = new UndirectedGraphNode(aNeighbor.label); LinkedList<String> result = new LinkedList<String>();
map.put(aNeighbor,copy);
map.get(curr).neighbors.add(copy); public List<String> findItinerary(String[][] tickets) {
queue.add(aNeighbor); for (String[] ticket : tickets) {
}else{ if (!map.containsKey(ticket[0])) {
map.get(curr).neighbors.add(map.get(aNeighbor)); PriorityQueue<String> q = new PriorityQueue<String>();
} map.put(ticket[0], q);
} }
map.get(ticket[0]).offer(ticket[1]);
} }
return newHead;
} dfs("JFK");
} return result;
}

public void dfs(String s) {


298.2 Java Solution 2 PriorityQueue<String> q = map.get(s);

while (q != null && !q.isEmpty()) {


public UndirectedGraphNode cloneGraph(UndirectedGraphNode node) { dfs(q.poll());
if(node == null) }
return null;
result.addFirst(s);
LinkedList<UndirectedGraphNode> queue = new LinkedList<UndirectedGraphNode>(); }
}
HashMap<UndirectedGraphNode,UndirectedGraphNode> map = new
HashMap<UndirectedGraphNode,UndirectedGraphNode>();

queue.offer(node);
while(!queue.isEmpty()){
UndirectedGraphNode top = queue.poll();
map.put(top, new UndirectedGraphNode(top.label));

for(UndirectedGraphNode n: top.neighbors){

Program Creek 565 | 568 Program Creek 566 | 568 567 | 568
300 Pow(x, n)
Problem:
Implement pow(x, n).
This is a great example to illustrate how to solve a problem during a technical interview. The first and second
solution exceeds time limit; the third and fourth are accepted.

300.1 Java Solution

public double myPow(double x, int n){


if(n==0)
return 1;

if(n<0){
return 1/helper(x, -n);
}

double v = helper(x, n/2);

if(n%2==0){
return v*v;
}else{
return v*v*x;
}
}

568 | 568

You might also like