Merged
Merged
Contains Duplicate
Easy
Given an integer array nums, return true if any value appears at least twice in the array, and return false if every element is distinct.
Example 1:
Example 2:
Example 3:
Constraints:
class Solution {
public boolean containsDuplicate(int[] nums) {
Set<Integer> set = new HashSet<>();
for(int num : nums) {
if(!set.add(num))
return true;
}
return false;
}
}
Given two strings s and t, return true if t is an anagram of s, and false otherwise.
An Anagram is a word or phrase formed by rearranging the letters of a different word or phrase, typically using all the original letters exactly once.
Example 1:
Example 2:
Constraints:
for(int n : chars) {
if(n != 0)
return false;
}
return true;
}
}
Follow up: What if the inputs contain Unicode characters? How would you adapt your
solution to such a case?
We can be used a map, or a array of size equal to the characterset size of unicode.
1. Two Sum
Easy
Given an array of integers nums and an integer target, return indices of the two numbers such that they add up to target.
You may assume that each input would have exactly one solution, and you may not use the same element twice.
Example 1:
Example 2:
Example 3:
Constraints:
Follow-up: Can you come up with an algorithm that is less than O(n2) time complexity?
class Solution {
public int[] twoSum(int[] nums, int target) {
int n = nums.length;
Map<Integer, Integer> map = new HashMap<>();
Given an array of strings strs, group the anagrams together. You can return the answer in any order.
An Anagram is a word or phrase formed by rearranging the letters of a different word or phrase, typically using all the original letters exactly once.
Example 1:
Example 2:
Example 3:
Constraints:
return res;
}
// 2
public List<List<String>> groupAnagrams(String[] strs) {
List<List<String>> res = new ArrayList<>();
Map<String, List<String>> mp = new HashMap<>();
for (String str : strs) {
char[] hash = new char[26];
for(char ch : str.toCharArray())
hash[ch-'a']++;
String r = new String(hash);
if (!mp.containsKey(r))
mp.put(r, new ArrayList<String>());
mp.get(r).add(str);
}
for (String key : mp.keySet()) {
res.add(mp.get(key));
}
return res;
}
Given an integer array nums and an integer k, return the k most frequent elements. You may return the answer in any order.
Example 1:
Example 2:
Constraints:
class Solution {
public int[] topKFrequent(int[] nums, int k) {
Map<Integer, Integer> mp = new HashMap<>();
int[] res = new int[k];
for(int num : nums) {
mp.put(num, mp.getOrDefault(num,0)+1);
}
PriorityQueue<Pair> pq = new PriorityQueue<>((a,b)->b.val-a.val);
for(int key : mp.keySet())
pq.offer(new Pair(key, mp.get(key)));
for(int i = 0; i < k; i++)
res[i] = pq.poll().key;
return res;
}
}
class Pair {
int key;
int val;
Pair(int k, int v) {
key = k;
val = v;
}
}
Given an integer array nums, return an array answer such that answer[i] is equal to the product of all the elements of nums except nums[i].
The product of any prefix or suffix of nums is guaranteed to fit in a 32-bit integer.
You must write an algorithm that runs in O(n) time and without using the division operation.
Example 1:
Example 2:
Constraints:
Follow up: Can you solve the problem in O(1) extra space complexity? (The output array
does not count as extra space for space complexity analysis.)
class Solution {
public int[] productExceptSelf(int[] nums) {
int n = nums.length;
int[] res = new int[n];
int pre = 1;
res[0] = 1;
for(int i = 0; i < n-1; i++) {
pre *= nums[i];
res[i+1] = pre;
}
int post = 1;
for(int i = n-1; i > 0; i--) {
post *= nums[i];
res[i-1] *= post;
}
return res;
}
}
Determine if a 9 x 9 Sudoku board is valid. Only the filled cells need to be validated according to the following rules:
Note:
A Sudoku board (partially filled) could be valid but is not necessarily solvable.
Only the filled cells need to be validated according to the mentioned rules.
Example 1:
Input: board =
[["5","3",".",".","7",".",".",".","."]
,["6",".",".","1","9","5",".",".","."]
,[".","9","8",".",".",".",".","6","."]
,["8",".",".",".","6",".",".",".","3"]
,["4",".",".","8",".","3",".",".","1"]
,["7",".",".",".","2",".",".",".","6"]
,[".","6",".",".",".",".","2","8","."]
,[".",".",".","4","1","9",".",".","5"]
,[".",".",".",".","8",".",".","7","9"]]
Output: true
Example 2:
Input: board =
[["8","3",".",".","7",".",".",".","."]
,["6",".",".","1","9","5",".",".","."]
,[".","9","8",".",".",".",".","6","."]
,["8",".",".",".","6",".",".",".","3"]
,["4",".",".","8",".","3",".",".","1"]
,["7",".",".",".","2",".",".",".","6"]
,[".","6",".",".",".",".","2","8","."]
,[".",".",".","4","1","9",".",".","5"]
,[".",".",".",".","8",".",".","7","9"]]
Output: false
Explanation: Same as Example 1, except with the 5 in the top left corner being modified to 8. Since there are two 8's in the top left 3x3 sub-box, it is invalid.
Constraints:
board.length == 9
board[i].length == 9
board[i][j] is a digit 1-9 or '.'.
// My Solution
class Solution {
public boolean isValidSudoku(char[][] board) {
return true;
}
Example1
Input: ["lint","code","love","you"]
Output: ["lint","code","love","you"]
Explanation:
One possible encode method is: "lint:;code:;love:;you"
Example2
/*
* @param str: A string
* @return: dcodes a single string to a list of strings
*/
public List<String> decode(String str) {
Given an unsorted array of integers nums, return the length of the longest consecutive elements sequence.
Example 1:
Example 2:
Constraints:
Resources
Youtube (https://youtu.be/shs0KM3wKv8)
Leetcode Discussion (https://leetcode.com/discuss/general-discussion/1068545/HASH-TABLE-and-MAP-POWERFUL-GUIDE-!!!)
A phrase is a palindrome if, after converting all uppercase letters into lowercase letters and removing all non-alphanumeric characters, it reads the same forward and backward.
Alphanumeric characters include letters and numbers.
Example 1:
Example 2:
Example 3:
Constraints:
return true;
}
}
Given a 1-indexed array of integers numbers that is already sorted in non-decreasing order, find two numbers such that they add up to a specific target number. Let these two
numbers be numbers[index1] and numbers[index2] where 1 <= index1 < index2 <= numbers.length.
Return the indices of the two numbers, index1 and index2, added by one as an integer array [index1, index2] of length 2.
The tests are generated such that there is exactly one solution. You may not use the same element twice.
Example 1:
Example 2:
Example 3:
Constraints:
15. 3Sum
Medium
Given an integer array nums, return all the triplets [nums[i], nums[j], nums[k]] such that i != j, i != k, and j != k, and nums[i] + nums[j] + nums[k] == 0.
Notice that the solution set must not contain duplicate triplets.
Example 1:
Example 2:
Input: nums = []
Output: []
Example 3:
Constraints:
You are given an integer array height of length n. There are n vertical lines drawn such that the two endpoints of the ith line are (i, 0) and (i, height[i]).
Find two lines that together with the x-axis form a container, such that the container contains the most water.
Example 1:
Example 2:
Constraints:
n == height.length
2 <= n <= 105
0 <= height[i] <= 104
class Solution {
public int maxArea(int[] height) {
int area = 0, maxArea = 0;
int left = 0, right = height.length-1;
return maxArea;
}
}
Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it can trap after raining.
Example 1:
Example 2:
Constraints:
n == height.length
Approach
First Approach:
- leftMax array to keep the max element on the left of the index
- rightMax array to keep the max element on the right of the index
- at each index take the min(leftMax, rightMax) - heigh[index], if it's greater than 0 add it to ans
- Time : O(N)
- Space: O(N)
Second Approach:
- instead of keep arrays to store the leftmax & rightMax, we can use two variables
- if leftMax <= rightMax
- try to update leftMax
- if min(leftMax, rightMax) - heigh[index] > 0, add it to ans
- move the left pointer ahead
- else
- same as above just replacing the left's by right
- decrement the right pointer
Solution
class Solution {
public int trap(int[] height) {
int left = 0, right = height.length-1;
int lMax = height[0], rMax = height[right];
int ans = 0;
while(left <= right) {
if(lMax <= rMax) {
lMax = Math.max(lMax, height[left]);
int val = Math.min(lMax, rMax)-height[left];
ans += val < 0 ? 0 : val;
left++;
} else {
rMax = Math.max(rMax, height[right]);
int val = Math.min(lMax, rMax)-height[right];
ans += val < 0 ? 0 : val;
right--;
}
}
return ans;
}
}
Complexity Analysis
- Time Complexity: O(N) -> go through each elements of the height array
- Space Complexity: O(1)
Resources
Youtube (https://youtu.be/-gjxg6Pln50)
Leetcode Discussion (https://leetcode.com/discuss/study-guide/1688903/Solved-all-two-pointers-problems-in-100-days.)
You are given an array prices where prices[i] is the price of a given stock on the ith day.
You want to maximize your profit by choosing a single day to buy one stock and choosing a different day in the future to sell that stock.
Return the maximum profit you can achieve from this transaction. If you cannot achieve any profit, return 0.
Example 1:
Input: prices = [7,1,5,3,6,4]
Output: 5
Explanation: Buy on day 2 (price = 1) and sell on day 5 (price = 6), profit = 6-1 = 5.
Note that buying on day 2 and selling on day 1 is not allowed because you must buy before you sell.
Example 2:
Constraints:
class Solution {
public int maxProfit(int[] prices) {
int n = prices.length;
if(n == 1) return 0;
int maxP = 0;
int l = 0, r = 1;
while(r < n) {
if(prices[l] < prices[r]) {
int profit = prices[r] - prices[l];
maxP = Math.max(maxP, profit);
} else
l = r;
r++;
}
return maxP;
}
}
Given a string s, find the length of the longest substring without repeating characters.
Example 1:
Input: s = "abcabcbb"
Output: 3
Explanation: The answer is "abc", with the length of 3.
Example 2:
Input: s = "bbbbb"
Output: 1
Explanation: The answer is "b", with the length of 1.
Example 3:
Input: s = "pwwkew"
Output: 3
Explanation: The answer is "wke", with the length of 3.
Notice that the answer must be a substring, "pwke" is a subsequence and not a substring.
Constraints:
class Solution {
public int lengthOfLongestSubstring(String s) {
Map<Character, Integer> mp = new HashMap<>();
int maxLen = 0, winStart = 0;
You are given a string s and an integer k. You can choose any character of the string and change it to any other uppercase English character. You can perform this operation at most
k times.
Return the length of the longest substring containing the same letter you can get after performing the above operations.
Example 1:
Input: s = "ABAB", k = 2
Output: 4
Explanation: Replace the two 'A's with two 'B's or vice versa.
Example 2:
Input: s = "AABABBA", k = 1
Output: 4
Explanation: Replace the one 'A' in the middle with 'B' and form "AABBBBA".
The substring "BBBB" has the longest repeating letters, which is 4.
Constraints:
Notes
- use a map to store the frequency
- maxRepeatingCharCount = max(maxRepeatingCharCount, mp.get(char))
- slide the left pointer until the equation satifies: windowEnd - windowStart + 1 - maxRepeatingCharCount > k
- maxLen = max(maxLen, windowEnd - windowStart + 1)
Solution:
class Solution {
public int characterReplacement(String s, int k) {
int windowStart = 0, maxLength = 0, mostRepeatingCharCount = 0;
return maxLength;
}
}
Given two strings s1 and s2, return true if s2 contains a permutation of s1, or false otherwise.
In other words, return true if one of s1's permutations is the substring of s2.
Example 1:
Example 2:
Constraints:
Approach
- 2 array of size 26 to keep count of chars present in both the strings[s1 and substring of s2]
- match keeps the number of characters matches in both s1 and substring of s2
- if matches = 26, we have a permutation in that window
- on each window, we check for conditions [ for both the chars(at left and at right) ]:
- increment s2Map[rightCharInd]++ and decrement s2Map[leftCharInd]--
- if the char's count are same increment the matches
- if the char's count differ by 1
- right: s1Map[rightCharInd] + 1 == s2Map[rightCharInd],
- left: s1Map[leftCharInd] - 1 == s2Map[leftCharInd] decrement the matches
Solution
class Solution {
public boolean checkInclusion(String s1, String s2) {
if(s1.length() > s2.length())
return false;
char[] s1Map = new char[26];
char[] s2Map = new char[26];
int matches = 0;
for(int i = 0; i < 26; i++) {
if(s1Map[i] == s2Map[i])
matches++;
}
int windowStart = 0;
for(int windowEnd = s1.length(); windowEnd < s2.length(); windowEnd++) {
if(matches == 26) return true;
int rightCharInd = s2.charAt(windowEnd)-'a';
s2Map[rightCharInd]++;
if(s1Map[rightCharInd] == s2Map[rightCharInd])
matches++;
else if(s1Map[rightCharInd] + 1 == s2Map[rightCharInd])
matches--;
windowStart++;
}
Complexity Analysis:
Time Complexity: O(s2.length())
Space Complexity: O(26) ~ O(1)
Given two strings s and t of lengths m and n respectively, return the minimum window substring of s such that every character in t (including duplicates) is included in the window. If
there is no such substring, return the empty string "".
The testcases will be generated such that the answer is unique.
Example 1:
Example 2:
Example 3:
Constraints:
m == s.length
n == t.length
1 <= m, n <= 105
s and t consist of uppercase and lowercase English letters.
Approach
- Try to increase the window untill we have all the characters of the pattern
- Once we get the pattern, we update the result if length is less than earlier
- Shrink the window while the window have all the required characters & update the result
Solution
Approach 1
class Solution {
public String minWindow(String s, String t) {
int winS = 0, winE = 0;
String ans = "";
Map<Character, Integer> tMp = new HashMap<>();
Map<Character, Integer> wMp = new HashMap<>();
for(char c : t.toCharArray()) {
tMp.put(c, tMp.getOrDefault(c, 0)+1);
}
while(winS < s.length() && winE < s.length()) {
char c = s.charAt(winE);
wMp.put(c, wMp.getOrDefault(c, 0)+1);
while(winS <= winE && satisfy(wMp, tMp)) {
if(ans == "")
ans = s.substring(winS, winE+1);
ans = (winE-winS+1) < ans.length()?s.substring(winS, winE+1):ans;
wMp.put(s.charAt(winS), wMp.get(s.charAt(winS))-1);
if(wMp.get(s.charAt(winS)) == 0)
wMp.remove(s.charAt(winS));
winS++;
}
winE++;
}
return ans;
}
Approach 2 (Optimized)
class Solution {
public String minWindow(String str, String pattern) {
int windowStart = 0, minLen = Integer.MAX_VALUE, matched = 0;
Map<Character, Integer> charFreqMap = new HashMap<>();
String res = "";
for (char ch : pattern.toCharArray())
charFreqMap.put(ch, charFreqMap.getOrDefault(ch, 0) + 1);
if (charFreqMap.containsKey(right)) {
charFreqMap.put(right, charFreqMap.get(right) - 1);
if (charFreqMap.get(right) == 0)
matched++;
}
Complexity Analysis
Approach 1:
- Time Complexity: O(N*K), N: length of str, K: length of pattern
- Space Complexity: O(K), K: length of pattern
Approach 2:
- Time Complexity: O(N), N: length of str
- Space Complexity: O(K), K: length of pattern
You are given an array of integers nums, there is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the
window. Each time the sliding window moves right by one position.
Example 1:
Input: nums = [1,3,-1,-3,5,3,6,7], k = 3
Output: [3,3,5,5,6,7]
Explanation:
Window position Max
--------------- -----
[1 3 -1] -3 5 3 6 7 3
1 [3 -1 -3] 5 3 6 7 3
1 3 [-1 -3 5] 3 6 7 5
1 3 -1 [-3 5 3] 6 7 5
1 3 -1 -3 [5 3 6] 7 6
1 3 -1 -3 5 [3 6 7] 7
Example 2:
Constraints:
Approach
- Use Deque, to keep the elements
- we'll keep the elemenet in decreasing order
- while the element at the first of the queue, i.e the index of the nums,
if it's out of the window, keep removing the element
- while the element at the last of the queue, i.e the index,
if it's less than equal to new element of the nums, keep removing the element
- insert the index of new element of nums
- if wE greater than k-1, then add the first element (index of the element in nums)
of the queue to res
Solution
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
int[] res = new int[nums.length - k + 1];
int wS = 0, s = 0;
ArrayDeque<Integer> q = new ArrayDeque<>();
// while the element at the last of the queue, i.e the index,
// if it's less than equal to new element of the nums,
// keep removing the element
while(!q.isEmpty() && nums[q.peekLast()] <= nums[wE])
q.pollLast();
Complexity Analysis
- Time Complexity: O(n)
- Space Complexity: O(k), where k < n
Resources
Leetcode - template (https://leetcode.com/problems/minimum-window-substring/discuss/26808/Here-is-a-10-line-template-that-can-solve-most-%27substring%27-problems)
Leetcode - Overview & Question bank (https://leetcode.com/discuss/study-guide/1773891/Sliding-Window-Technique-and-Question-Bank)
Youtube Playlist - Hindi (https://youtube.com/playlist?list=PL_z_8CaSLPWeM8BDJmIYDaoQ5zuwyxnfj)
Youtube Playlist - Neetcode (https://youtube.com/playlist?list=PLot-Xpze53leOBgcVsJBEGrHPd_7x_koV)
Given a string s containing just the characters '(', ')', '{', '}', '[' and ']', determine if the input string is valid.
Example 1:
Input: s = "()"
Output: true
Example 2:
Input: s = "()[]{}"
Output: true
Example 3:
Input: s = "(]"
Output: false
Constraints:
class Solution {
public boolean isValid(String s) {
Stack<Character> st = new Stack<>();
return st.empty();
}
}
Design a stack that supports push, pop, top, and retrieving the minimum element in constant time.
Example 1:
Input
["MinStack","push","push","push","getMin","pop","top","getMin"]
[[],[-2],[0],[-3],[],[],[],[]]
Output
[null,null,null,null,-3,null,0,-2]
Explanation
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin(); // return -3
minStack.pop();
minStack.top(); // return 0
minStack.getMin(); // return -2
Constraints:
Pair(int v, int m) {
val = v;
min = m;
}
void setVal(int v) {
val = v;
}
void setMin(int m) {
min = m;
}
}
class MinStack {
Stack<Pair> st;
public MinStack() {
st = new Stack<>();
}
/**
* Your MinStack object will be instantiated and called as such:
* MinStack obj = new MinStack();
* obj.push(val);
* obj.pop();
* int param_3 = obj.top();
* int param_4 = obj.getMin();
*/
Valid operators are +, -, *, and /. Each operand may be an integer or another expression.
Note that division between two integers should truncate toward zero.
It is guaranteed that the given RPN expression is always valid. That means the expression would always evaluate to a result, and there will not be any division by zero operation.
Example 1:
Example 2:
Example 3:
Constraints:
Solution
class Solution {
public int evalRPN(String[] tokens) {
Stack<Integer> st = new Stack<>();
for(String s : tokens) {
if(s.equals("+")) {
st.push(st.pop()+st.pop());
} else if(s.equals("-")) {
int n2 = st.pop();
int n1 = st.pop();
st.push(n1-n2);
} else if(s.equals("*")) {
st.push(st.pop()*st.pop());
} else if(s.equals("/")) {
int n2 = st.pop();
int n1 = st.pop();
st.push(n1/n2);
} else {
st.push(Integer.parseInt(s));
}
}
return st.peek();
}
}
Comlexity Analysis
Time Complexity: O(N) -> traversing through all the tokens
Space Complexity: O(N) -> for the stack
22. Generate Parentheses
Medium
Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses.
Example 1:
Input: n = 3
Output: ["((()))","(()())","(())()","()(())","()()()"]
Example 2:
Input: n = 1
Output: ["()"]
Constraints:
1 <= n <= 8
Approach
- Backtracking
- add '(' always and add ')' only if count('(') > count(')')
- add the string into the result when count('(') > count(')') && count('(') == n
- base case: count('(') > n || count(')') > n
Solution
class Solution {
public List<String> generateParenthesis(int n) {
List<String> ans = new ArrayList<>();
generate(0, n, 0, 0, ans, "");
return ans;
}
private void generate(int index, int n, int lCount, int rCount, List<String> ans, String op) {
if(lCount > n || rCount > n)
return;
if(lCount == rCount && lCount == n) {
ans.add(op);
}
if(lCount > rCount) {
String op1 = op + ")";
generate(index+1, n, lCount, rCount+1, ans, op1);
}
String op2 = op + "(";
generate(index+1, n, lCount+1, rCount, ans, op2);
}
}
Example 1:
Example 2:
Example 3:
Constraints:
Approach
- Use a stack to keep temperatures and indices
- We'll check while peek element is less the current temperature
- We'll pop and res[popped Index] = i-popped Index;
- push each element and index to the stack
return res;
}
}
Complexity Analysis
- Time Complexity: O(N)
At first glance, it may look like the time complexity of this algorithm should be O(N^2),
because there is a nested while loop inside the for loop. However, each element can only be added to the stack once,
which means the stack is limited to N pops. Every iteration of the while loop uses 1 pop,
which means the while loop will not iterate more than N times in total, across all iterations of the for loop.
An easier way to think about this is that in the worst case, every element will be pushed and popped once.
This gives a time complexity of O(2*N) = O(N).
- Space Complexity: O(N)
If the input was non-increasing, then no element would ever be popped from the stack,
and the stack would grow to a size of N elements at the end.
There are n cars going to the same destination along a one-lane road. The destination is target miles away.
You are given two integer array position and speed, both of length n, where position[i] is the position of the ith car and speed[i] is the speed of the ith car (in miles per hour).
A car can never pass another car ahead of it, but it can catch up to it and drive bumper to bumper at the same speed. The faster car will slow down to match the slower car's speed.
The distance between these two cars is ignored (i.e., they are assumed to have the same position).
A car fleet is some non-empty set of cars driving at the same position and same speed. Note that a single car is also a car fleet.
If a car catches up to a car fleet right at the destination point, it will still be considered as one car fleet.
Return the number of car fleets that will arrive at the destination.
Example 1:
Example 2:
Example 3:
Constraints:
n == position.length == speed.length
Approach
Solution
class Solution {
// 1
public int carFleet(int target, int[] position, int[] speed) {
int n = position.length, res = 0;
double[][] cars = new double[n][2];
Complexity Analysis
- Time Complexity:O(NlogN) -> sorting
- Space Complexity: O(N)
Given an array of integers heights representing the histogram's bar height where the width of each bar is 1, return the area of the largest rectangle in the histogram.
Example 1:
Constraints:
Approach
- Monotonic Stack
- store index and height in the stack
- while the top element is greater in height than the new element,
- keep poping the top element and compare the area with maxArea
- start will have the index of the poped element(new element can be extended towards the left)
- push start and height into the stack
- while stack is not empty,
- keep poping and compare the area with maxArea
- return maxArea
Solution
class Solution {
public int largestRectangleArea(int[] heights) {
int maxArea = 0;
Stack<int[]> st = new Stack<>();
for(int i = 0; i < heights.length; i++) {
int start = i;
while(!st.isEmpty() && st.peek()[1] > heights[i]) {
int[] pair = st.pop();
maxArea = Math.max(maxArea, pair[1] * (i-pair[0]));
start = pair[0];
}
st.push(new int[]{start, heights[i]});
}
while(!st.isEmpty()) {
int[] pair = st.pop();
maxArea = Math.max(maxArea, pair[1] * (heights.length-pair[0]));
}
return maxArea;
}
}
Complexity Analysis
- Time Complexity: O(N)
- Space Complexity: O(N)
Resources
Articles
Geeksforgeeks (https://www.geeksforgeeks.org/stack-data-structure/)
A-comprehensive-guide-and-template-for-monotonic-stack-based-problems (https://leetcode.com/discuss/study-guide/2347639/A-comprehensive-guide-and-template-for-
monotonic-stack-based-problems)
Videos
Playlist (https://youtube.com/playlist?list=PL6Zs6LgrJj3vWOf01wMHiTy9IFufptfG3)
Playlist - Hindi (https://youtube.com/playlist?list=PLDzeHZWIZsTrhXYYtx4z8-u8zA-DzuVsj)
Given an array of integers nums which is sorted in ascending order, and an integer target, write a function to search target in nums. If target exists, then return its index. Otherwise,
return -1.
Example 1:
Example 2:
Constraints:
class Solution {
public int search(int[] nums, int target) {
int l = 0, r = nums.length-1;
while(l <= r) {
int mid = l + (r - l)/2;
if(nums[mid] == target)
return mid;
else if(nums[mid] < target)
l = mid + 1;
else
r = mid - 1;
}
return -1;
}
}
Write an efficient algorithm that searches for a value target in an m x n integer matrix matrix. This matrix has the following properties:
Integers in each row are sorted from left to right. The first integer of each row is greater than the last integer of the previous row.
Example 1:
Input: matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 3
Output: true
Example 2:
Constraints:
m == matrix.length
n == matrix[i].length
1 <= m, n <= 100
-104 <= matrix[i][j], target <= 104
Approach
1st:
- keep two pointer one for row, other for column
- initialize tem to point to the last element of the 1st row
- if the element is equal to target then return true
- else if element is < target then move the row pointer downward
- else shift the column pointer to left
2nd:
[It would work only when the element at 1st index of next row should be greater then last element of the previous row]
- left pointer at 0, right at n*m-1 (at last element of the matrix)
- do the binarysearch
- target element can be find using
- rowIndex = mid / number of elements in each row
- colIndex = mid % number of elements in each row
Solution
class Solution {
// worst case go through O(n+m) elements
public boolean searchMatrix(int[][] matrix, int target) {
int m = matrix.length, n = matrix[0].length;
int row = 0, col = n-1;
while(row >= 0 && row < m && col >= 0 && col < n) {
int val = matrix[row][col];
if(val == target)
return true;
else if(val < target)
row++;
else
col--;
}
return false;
}
Complexity Analysis
- Time Complexity:
- 1st approach: O(n+m)
- 2nd approach: O(log(n*m))
- Space Coplexity: O(1) for both approaches
Koko loves to eat bananas. There are n piles of bananas, the ith pile has piles[i] bananas. The guards have gone and will come back in h hours.
Koko can decide her bananas-per-hour eating speed of k. Each hour, she chooses some pile of bananas and eats k bananas from that pile. If the pile has less than k bananas, she
eats all of them instead and will not eat any more bananas during this hour.
Koko likes to eat slowly but still wants to finish eating all the bananas before the guards return.
Return the minimum integer k such that she can eat all the bananas within h hours.
Example 1:
Example 2:
Input: piles = [30,11,23,4,20], h = 5
Output: 30
Example 3:
Constraints:
Approach
- Binary search on range (1, max(pile))
- while the condition satisfies go towards left half
- else go towards right half
Solution
class Solution {
public int minEatingSpeed(int[] piles, int h) {
int left = 1, right = piles[0];
for(int pile : piles) {
if(pile < left)
left = pile;
if(pile > right)
right = pile;
}
int result = right;
while(left <= right) {
int mid = left + (right-left)/2;
if(isSatisfy(piles, mid, h)) {
result = Math.min(result, mid);
right = mid-1;
} else {
left = mid+1;
}
}
return result;
}
Complexity Analysis
- Time Complexity: O(n*logm), m: max(piles)
- Space Complexity: O(1)
33. Search in Rotated Sorted Array
Medium
There is an integer array nums sorted in ascending order (with distinct values).
Prior to being passed to your function, nums is possibly rotated at an unknown pivot index k (1 <= k < nums.length) such that the resulting array is [nums[k], nums[k+1], ..., nums[n-1],
nums[0], nums[1], ..., nums[k-1]] (0-indexed). For example, [0,1,2,4,5,6,7] might be rotated at pivot index 3 and become [4,5,6,7,0,1,2].
Given the array nums after the possible rotation and an integer target, return the index of target if it is in nums, or -1 if it is not in nums.
Example 1:
Example 2:
Example 3:
Constraints:
Approach
Modified Binary Search
Solution
class Solution {
public int search(int[] nums, int target) {
int left = 0, right = nums.length-1;
if(nums[mid] == target)
return mid;
// left sorted portion
if(nums[left] <= nums[mid]) {
if(target < nums[left] || target > nums[mid])
left = mid+1;
else
right = mid-1;
}
// right sorted portion
else {
if(target < nums[mid] || target > nums[right])
right = mid-1;
else
left = mid+1;
}
}
return -1;
}
}
Complexity Analysis
- Time Complexity: O(logN)
- Space Complexity: O(1)
Suppose an array of length n sorted in ascending order is rotated between 1 and n times. For example, the array nums = [0,1,2,4,5,6,7] might become:
Notice that rotating an array [a[0], a[1], a[2], ..., a[n-1]] 1 time results in the array [a[n-1], a[0], a[1], a[2], ..., a[n-2]].
Given the sorted rotated array nums of unique elements, return the minimum element of this array.
Example 1:
Example 2:
Example 3:
Input: nums = [11,13,15,17]
Output: 11
Explanation: The original array was [11,13,15,17] and it was rotated 4 times.
Constraints:
n == nums.length
1 <= n <= 5000
-5000 <= nums[i] <= 5000
All the integers of nums are unique.
nums is sorted and rotated between 1 and n times.
Approach
Modified Binary Search
Solution
class Solution {
public int findMin(int[] nums) {
int n = nums.length;
int start = 0, end = n-1;
int res = 0;
while(start <= end) {
int mid = start + (end - start)/2;
int prev = (mid-1+n)%n, next = (mid+1)%n;
if(nums[mid]<nums[prev] && nums[mid]<nums[next])
return nums[mid];
else if(nums[end] <= nums[mid])
start = mid+1;
else
end = mid-1;
}
return nums[res];
}
}
Complexity Analysis
- Time Complexity: O(logN)
- Space Complexity: O(1)
Design a time-based key-value data structure that can store multiple values for the same key at different time stamps and retrieve the key's value at a certain timestamp.
Example 1:
Input
["TimeMap", "set", "get", "get", "set", "get", "get"]
[[], ["foo", "bar", 1], ["foo", 1], ["foo", 3], ["foo", "bar2", 4], ["foo", 4], ["foo", 5]]
Output
[null, null, "bar", "bar", null, "bar2", "bar2"]
Explanation
TimeMap timeMap = new TimeMap();
timeMap.set("foo", "bar", 1); // store the key "foo" and value "bar" along with timestamp = 1.
timeMap.get("foo", 1); // return "bar"
timeMap.get("foo", 3); // return "bar", since there is no value corresponding to foo at timestamp 3 and timestamp 2, then the
timeMap.set("foo", "bar2", 4); // store the key "foo" and value "bar2" along with timestamp = 4.
timeMap.get("foo", 4); // return "bar2"
timeMap.get("foo", 5); // return "bar2"
Constraints:
Approach
Solution
class TimeMap {
class Pair {
int timestamp;
String value;
public TimeMap() {
mp = new HashMap<>();
}
ans = list.get(index).value;
return ans;
}
/**
* Your TimeMap object will be instantiated and called as such:
* TimeMap obj = new TimeMap();
* obj.set(key,value,timestamp);
* String param_2 = obj.get(key,timestamp);
*/
public class TimeMap {
Complexity Analysis
- Time Complexity:
- Space Complexity:
Given two sorted arrays nums1 and nums2 of size m and n respectively, return the median of the two sorted arrays.
Example 1:
Example 2:
Constraints:
nums1.length == m
nums2.length == n
0 <= m <= 1000
0 <= n <= 1000
1 <= m + n <= 2000
Approach
Solution
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
if(nums1.length > nums2.length)
return findMedianSortedArrays(nums2, nums1);
int total = nums1.length + nums2.length;
int half = (total + 1) / 2;
int l = 0, r = nums1.length;
double result = 0d;
while(l <= r) {
int i = l + (r - l) / 2;
int j = half - i;
int nums1L = i > 0 ? nums1[i-1]:Integer.MIN_VALUE;
int nums1R = i < nums1.length ? nums1[i]:Integer.MAX_VALUE;
int nums2L = j > 0 ? nums2[j-1]:Integer.MIN_VALUE;
int nums2R = j < nums2.length ? nums2[j]:Integer.MAX_VALUE;
Complexity Analysis
- Time Complexity: O(log(m+n))
- Space Complexity: O(1)
Resources
Articles:
Binary-Search-101-The-Ultimate-Binary-Search-Handbook (https://leetcode.com/problems/binary-search/discuss/423162/Binary-Search-101-The-Ultimate-Binary-Search-
Handbook)
Python-Clear-explanation-Powerful-Ultimate-Binary-Search-Template.-Solved-many-problems. (https://leetcode.com/problems/koko-eating-bananas/discuss/769702/Python-
Clear-explanation-Powerful-Ultimate-Binary-Search-Template.-Solved-many-problems.)
JavaC%2B%2BPython-Binary-Search (https://leetcode.com/problems/koko-eating-bananas/discuss/152324/JavaC%2B%2BPython-Binary-Search)
Binary-Search-for-Beginners-Problems-or-Patterns-or-Sample-solutions (https://leetcode.com/discuss/study-guide/691825/Binary-Search-for-Beginners-Problems-or-Patterns-
or-Sample-solutions)
5-variations-of-Binary-search-(A-Self-Note) (https://leetcode.com/discuss/study-guide/1322500/5-variations-of-Binary-search-(A-Self-Note))
Videos:
Binary Search Introduction (https://youtu.be/P3YID7liBug)
Neetcode Playlist (https://youtube.com/playlist?list=PLot-Xpze53leNZQd0iINpD-MAhMOMzWvO)
Example 1:
Example 2:
Example 3:
Input: head = []
Output: []
Constraints:
Follow up: A linked list can be reversed either iteratively or recursively. Could you
implement both?
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode reverseList(ListNode head) {
ListNode curr = head, next = head, prev = null;
while(curr != null) {
next = curr.next;
curr.next = prev;
prev = curr;
curr = next;
}
return prev;
}
}
You are given the heads of two sorted linked lists list1 and list2.
Merge the two lists in a one sorted list. The list should be made by splicing together the nodes of the first two lists.
Example 1:
Input: list1 = [1,2,4], list2 = [1,3,4]
Output: [1,1,2,3,4,4]
Example 2:
Input: list1 = [], list2 = []
Output: []
Example 3:
Input: list1 = [], list2 = [0]
Output: [0]
Constraints:
The number of nodes in both lists is in the range [0, 50]. -100 <= Node.val <= 100 Both list1 and list2 are sorted in non-decreasing order.
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
ListNode dummy = new ListNode(0);
ListNode result = dummy;
while(list1 != null && list2 != null) {
if(list1.val < list2.val) {
dummy.next = list1;
dummy = dummy.next;
list1 = list1.next;
} else {
dummy.next = list2;
dummy = dummy.next;
list2 = list2.next;
}
}
if(list1 != null) {
dummy.next = list1;
}
if(list2 != null) {
dummy.next = list2;
}
return result.next;
}
}
143. Reorder List
Medium
You are given the head of a singly linked-list. The list can be represented as:
L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → … You may not modify the values in the list's nodes. Only nodes themselves may be changed.
Example 1:
Example 2:
Constraints:
Approach
- Reverse the other half(mid to end)
- 2 pointers one from the head other from the reverse head of other list
- use temp variable to keep the next pointers of both the list
- 1st list's next points to 2nd list & 2nd list's next point to the temp variable containing the next of the 1st list
- move both the pointers
Solution
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public void reorderList(ListNode head) {
ListNode slow = head, fast = head.next;
while(second != null) {
ListNode tmp1 = first.next, tmp2 = second.next;
first.next = second;
second.next = tmp1;
first = tmp1;
second = tmp2;
}
while(curr != null) {
next = curr.next;
curr.next = prev;
prev = curr;
curr = next;
}
return prev;
}
}
Complexity Analysis
- Time Complexity: O(2*N) ~ O(N)
- Space Complexity: O(1)
Given the head of a linked list, remove the nth node from the end of the list and return its head.
Example 1:
Example 2:
Input: head = [1], n = 1
Output: []
Example 3:
Constraints:
1 <= sz <= 30
0 <= Node.val <= 100
1 <= n <= sz
Approach
- 2 pointers approach
- dummy head for so that removing head would be easier
- fast pointer would be ahead by n nodes
- slow and fast will start moving until fast reach the last element
- slow's next node would be the one we need to remove
Solution
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummyHead = new ListNode(0);
dummyHead.next = head;
ListNode slow = dummyHead, fast = dummyHead;
while(n > 0) {
fast = fast.next;
n--;
}
slow.next = slow.next.next;
return dummyHead.next;
}
}
Complexity Analysis
- Time Complexity: O(N) , one pass only
- Space Complexity: O(1)
A linked list of length n is given such that each node contains an additional random pointer, which could point to any node in the list, or null.
Construct a deep copy of the list. The deep copy should consist of exactly n brand new nodes, where each new node has its value set to the value of its corresponding original node.
Both the next and random pointer of the new nodes should point to new nodes in the copied list such that the pointers in the original list and copied list represent the same list state.
None of the pointers in the new list should point to nodes in the original list.
For example, if there are two nodes X and Y in the original list, where X.random --> Y, then for the corresponding two nodes x and y in the copied list, x.random --> y.
The linked list is represented in the input/output as a list of n nodes. Each node is represented as a pair of [val, random_index] where:
Your code will only be given the head of the original linked list.
Example 1:
Example 2:
Example 3:
Constraints:
Approach
- Step 1: Duplicate each node such that old1->new1->old2->new2 ...
- Step 2: Random pointer of new = Random pointer of old's next
- Step 3: Seperate the the nodes to form old1->old2.. & new1->new2..
Solution
/*
// Definition for a Node.
class Node {
int val;
Node next;
Node random;
class Solution {
public Node copyRandomList(Node head) {
if(head == null)
return null;
return newListHead;
}
}
Complexity Analysis
- Time Complexity: O(N+2*N+N) ~ O(N)
- Space Complexity: O(1), no extra memory is used (memory used is for new list only)
2. Add Two Numbers
Medium
You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order, and each of their nodes contains a single digit. Add the two
numbers and return the sum as a linked list.
You may assume the two numbers do not contain any leading zero, except the number 0 itself.
Example 1:
Example 2:
Example 3:
Constraints:
The number of nodes in each linked list is in the range [1, 100].
0 <= Node.val <= 9
It is guaranteed that the list represents a number that does not have leading zeros.
Approach
- Three pointers, one for each given list and 3rd one for resultant list
- untill both the pointers pointing to given lists are null or carry > 0
- add new node to the resultant list
Solution
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode res = new ListNode(0);
ListNode curr1 = l1, curr2 = l2, curr3 = res;
int carry = 0;
while(curr1 != null || curr2 != null || carry > 0) {
int v1 = curr1 == null ? 0 : curr1.val;
int v2 = curr2 == null ? 0 : curr2.val;
int sum = v1 + v2 + carry;
carry = sum / 10;
curr3.next = new ListNode(sum % 10);
curr3 = curr3.next;
curr1 = curr1 == null ? curr1 : curr1.next;
curr2 = curr2 == null ? curr2 : curr2.next;
}
return res.next;
}
}
Complexity Analysis
- Time Complexity: O(max(len(list1, list2))
- Space Complexity: O(max(len(list1, list2))
Given head, the head of a linked list, determine if the linked list has a cycle in it.
There is a cycle in a linked list if there is some node in the list that can be reached again by continuously following the next pointer. Internally, pos is used to denote the index of the
node that tail's next pointer is connected to. Note that pos is not passed as a parameter.
Return true if there is a cycle in the linked list. Otherwise, return false.
Example 1:
Example 2:
Example 3:
Input: head = [1], pos = -1
Output: false
Explanation: There is no cycle in the linked list.
Constraints:
The number of the nodes in the list is in the range [0, 104].
-105 <= Node.val <= 105
pos is -1 or a valid index in the linked-list.
Follow up: Can you solve it using O(1) (i.e. constant) memory?
Approach
- slow and fast pointer
- move fast twice that of slow
- break if fast reach null or fast becomes equal to slow
- if slow == fast, thenn has a cycle otherwise no cycle
Solution
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public boolean hasCycle(ListNode head) {
if(head == null)
return false;
ListNode slow = head, fast = head.next;
Complexity Analysis
- Time Complexity: O(N), N : numbers of nodes in the list
- Space Complexity: O(1)
Given an array of integers nums containing n + 1 integers where each integer is in the range [1, n] inclusive.
There is only one repeated number in nums, return this repeated number.
You must solve the problem without modifying the array nums and uses only constant extra space.
Example 1:
Example 2:
Constraints:
Follow up:
How can we prove that at least one duplicate number must exist in nums?
Can you solve the problem in linear runtime complexity?
Approach
- slow and fast pointer, similar to cycle in link list
Solution
class Solution {
public int findDuplicate(int[] nums) {
slow = nums[0];
while(slow != fast) {
slow = nums[slow];
fast = nums[fast];
}
return slow;
}
}
Complexity Analysis
- Time Complexity: O(N)
- Space Complexity: O(1)
LRUCache(int capacity) Initialize the LRU cache with positive size capacity.
int get(int key) Return the value of the key if the key exists, otherwise return -1.
void put(int key, int value) Update the value of the key if the key exists. Otherwise, add the key-value pair to the cache. If the number of keys exceeds the capacity
from this operation, evict the least recently used key.
The functions get and put must each run in O(1) average time complexity.
Example 1:
Input
["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"]
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
Output
[null, null, null, 1, null, -1, null, -1, 3, 4]
Explanation
LRUCache lRUCache = new LRUCache(2);
lRUCache.put(1, 1); // cache is {1=1}
lRUCache.put(2, 2); // cache is {1=1, 2=2}
lRUCache.get(1); // return 1
lRUCache.put(3, 3); // LRU key was 2, evicts key 2, cache is {1=1, 3=3}
lRUCache.get(2); // returns -1 (not found)
lRUCache.put(4, 4); // LRU key was 1, evicts key 1, cache is {4=4, 3=3}
lRUCache.get(1); // return -1 (not found)
lRUCache.get(3); // return 3
lRUCache.get(4); // return 4
Constraints:
Approach
- Doublely linkedlist, it allows O(1) deletion of a given node
- Map to keep the key mapped to a node, getting the value for a key at O(1) time
- Keeping head and tail of the linked list
- add at head and remove from tail(if size exceeds)
- get method:
- if map doesn't contain the key return -1
- else get the node, remove it, add it (it'll add it to the head of the list), return the value
- put method:
- if map already contains the key, remove the node
- size of map = size, then remove the node at tail
- insert the new node
Solution
/*
* Hepler class
* Node to create doublely linked list
*/
class Node {
int key;
int val;
Node prev;
Node next;
Node(int key, int val) {
this.key = key;
this.val = val;
}
}
class LRUCache {
Node head = new Node(0, 0);
Node tail = new Node(0, 0);
Map<Integer, Node> mp;
int size;
/**
* Your LRUCache object will be instantiated and called as such:
* LRUCache obj = new LRUCache(capacity);
* int param_1 = obj.get(key);
* obj.put(key,value);
*/
Complexity Analysis
- Time Complexity: (on average)
- get() : O(1)
- put() : O(1)
- Space Complexity:
- ~ O(N) for map and doublely linkedlist (over all)
- get() : O(1)
- put() : O(1)
You are given an array of k linked-lists lists, each linked-list is sorted in ascending order.
Merge all the linked-lists into one sorted linked-list and return it.
Example 1:
Example 2:
Input: lists = []
Output: []
Example 3:
Constraints:
k == lists.length
0 <= k <= 104
0 <= lists[i].length <= 500
-104 <= lists[i][j] <= 104
lists[i] is sorted in ascending order.
Approach
- Create a function to merge two sorted lists
- Use it to merge all the given lists
Sub approach 1:
- we can merge two lists then use the merge list as new list and merge it with next given list
Sub approach 2:
- we can merge all the lists as a group of 2 lists untill we're left with 1 final list
Solution
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
int k = lists.length;
if(k == 0)
return null;
int i = 0;
while(i+1<k) {
ListNode l1 = lists[i], l2 = lists[i+1];
lists[i+1] = merge2LL(l1, l2);
i++;
}
return lists[k-1];
}
if(l1 == null)
tmp.next = l2;
if(l2 == null)
tmp.next = l1;
return dummyHead.next;
}
}
Optimized
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
return partion(lists, 0, lists.length - 1);
}
Complexity Analysis
- Time complexity : O(Nlogk) where k is the number of linked lists.
We can merge two sorted linked list in O(n) time where nn is the total number of nodes in two lists.
Sum up the merge process and we can get: O(Nlogk)
- Space complexity : O(logk) for recursive call stack
We can merge two sorted linked lists in O(1) space.
25. Reverse Nodes in k-Group
(https://leetcode.com/problems/reverse-
nodes-in-k-group/)
Hard
Given the head of a linked list, reverse the nodes of the list k at a time, and return the modified list.
k is a positive integer and is less than or equal to the length of the linked list. If the number of nodes is not a multiple of k then left-out nodes, in the end, should remain as it is.
You may not alter the values in the list's nodes, only nodes themselves may be changed.
Example 1:
Example 2:
Constraints:
Follow-up: Can you solve the problem in O(1) extra memory space?
Approach
- Reusing reverse linkedlist function
- dummy root, it's next point to head of given linkedlist
- use two pointer curr and prev
- storing firstNode of every group
- index to find whether we have the complete group or not, as it determines whether we have reverse the that group or not
- if complete group is there prev.next points to the newly reversed list and
the prev points to firstNode(prev group, which is the last node of the prev group)
- else prev.next points to firstNode
Solution
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
while(curr != null) {
ListNode tail = curr; // keep track of the 1st element of each group
int listIndex = 0;
Complexity Analysis
- Time Complexity: O(n)
- Space Complexity: O(1)
Resources
226. Invert Binary Tree
(https://leetcode.com/problems/invert-binary-
tree/)
Given the root of a binary tree, invert the tree, and return its root.
Example 1:
Input: root = [4,2,7,1,3,6,9]
Output: [4,7,2,9,6,3,1]
Example 2:
Input: root = [2,1,3]
Output: [2,3,1]
Example 3:
Input: root = []
Output: []
Constraints:
Approach
- Recursion
- store one pointer to right or left subtree
- swap left with right and make call recursively
Solution
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public TreeNode invertTree(TreeNode root) {
if(root == null)
return null;
TreeNode tmp = root.right;
root.right = invertTree(root.left);
root.left = invertTree(tmp);
return root;
}
}
Complexity Analysis
- Time Complexity: O(N)
- Space Complexity: O(H), atmost height of tree would be the number of recursive call stack at a given point of time
A binary tree's maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node.
Example 1:
Input: root = [3,9,20,null,null,15,7]
Output: 3
Example 2:
Input: root = [1,null,2]
Output: 2
Constraints:
Approach
- Recursion
- if node = null return 0
- return 1 + max(leftHeight, rightHeight)
Solution
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public int maxDepth(TreeNode root) {
if(root == null)
return 0;
return 1 + Math.max(maxDepth(root.left), maxDepth(root.right));
}
}
Complexity Analysis
- Time Complexity: O(N)
- Space Complexity: O(H), height of the tree
Given the root of a binary tree, return the length of the diameter of the tree.
The diameter of a binary tree is the length of the longest path between any two nodes in a tree. This path may or may not pass through the root.
The length of a path between two nodes is represented by the number of edges between them.
Example 1:
Example 2:
Constraints:
a binary tree in which the left and right subtrees of every node differ in height by no more than 1.
Example 1:
Example 2:
Example 3:
Input: root = []
Output: true
Constraints:
Given the roots of two binary trees p and q, write a function to check if they are the same or not.
Two binary trees are considered the same if they are structurally identical, and the nodes have the same value.
Example 1:
Example 2:
Example 3:
Constraints:
Given the roots of two binary trees root and subRoot, return true if there is a subtree of root with the same structure and node values of subRoot and false otherwise.
A subtree of a binary tree tree is a tree that consists of a node in tree and all of this node's descendants. The tree tree could also be considered as a subtree of itself.
Example 1:
Example 2:
Constraints:
The number of nodes in the root tree is in the range [1, 2000].
The number of nodes in the subRoot tree is in the range [1, 1000].
-104 <= root.val <= 104
-104 <= subRoot.val <= 104
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public boolean isSubtree(TreeNode root, TreeNode subRoot) {
if(root == null && subRoot == null)
return true;
if(root == null || subRoot == null)
return false;
while(!q.isEmpty()) {
TreeNode node = q.poll();
if(node.val == subRoot.val) {
if(isSameTree(node, subRoot))
return true;
}
if(node.left != null)
q.offer(node.left);
if(node.right != null)
q.offer(node.right);
}
return false;
}
Given a binary search tree (BST), find the lowest common ancestor (LCA) of two given nodes in the BST.
According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes p and q as the lowest node in T that has both p and q as descendants
(where we allow a node to be a descendant of itself).”
Example 1:
Input: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
Output: 6
Explanation: The LCA of nodes 2 and 8 is 6.
Example 2:
Constraints:
Approach
- Recursion
- if root's val < p's val & q's val then reduce the problem to right subtree of root
- else if root's val > p's val & q's val then reduce the problem to left subtree of root
- else return root (if p's val or q's val equal to root's val or for p & q lies in different subtree of the root)
Solution
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root == null)
return null;
int val = root.val;
if(val < p.val && val < q.val)
return lowestCommonAncestor(root.right, p, q);
else if(val > p.val && val > q.val)
return lowestCommonAncestor(root.left, p, q);
return root;
}
}
Complexity Analysis
- Time Complexity: O(logN)
- Space Complexity: O(logN) recursive calls
Given the root of a binary tree, return the level order traversal of its nodes' values. (i.e., from left to right, level by level).
Example 1:
Example 2:
Example 3:
Input: root = []
Output: []
Constraints:
Approach
- Use Queue to insert the nodes
- for each level we'll poll node and check if left or right of it is not null then add left or right of it to the queue
Solution
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> result = new ArrayList<>();
if(root == null)
return result;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while(!queue.isEmpty()) {
int levelSize = queue.size();
List<Integer> currLevel = new ArrayList<>(levelSize);
result.add(currLevel);
}
return result;
}
}
Complexity Analysis
- Time Complexity: O(N)
- Space Complexity: O(N), max number of nodes in a level
Given the root of a binary tree, imagine yourself standing on the right side of it, return the values of the nodes you can see ordered from top to bottom.
Example 1:
Example 2:
Input: root = [1,null,3]
Output: [1,3]
Example 3:
Input: root = []
Output: []
Constraints:
Approach
- BFS
- Queue
- add the last element of each level into the result list
Solution
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<Integer> rightSideView(TreeNode root) {
List<Integer> res = new ArrayList<>();
if(root == null)
return res;
while(!queue.isEmpty()) {
int levelSize = queue.size();
for(int i = 0; i < levelSize; i++) {
TreeNode currNode = queue.poll();
if(currNode.left != null)
queue.offer(currNode.left);
if(currNode.right != null)
queue.offer(currNode.right);
if(i == levelSize-1)
res.add(currNode.val);
}
}
return res;
}
}
Complexity Analysis
- Time Complexity: O(N)
- Space Complexity: O(N)
Share Given a binary tree root, a node X in the tree is named good if in the path from root to X there are no nodes with a value greater than X.
Example 1:
Example 2:
Example 3:
Constraints:
The number of nodes in the binary tree is in the range [1, 10^5].
Each node's value is between [-104, 104].
Approach
- check if the node is null
- if node.val >= previously send max, res will be one
- res += left Subtree call with updated max
- res += right Subtree call with updated max
Solution
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public int goodNodes(TreeNode root) {
return goodNodes(root, Integer.MIN_VALUE);
}
Complexity Analysis
- Time Complexity: O(N)
- Space Complexity: O(height)
Given the root of a binary tree, determine if it is a valid binary search tree (BST).
The left subtree of a node contains only nodes with keys less than the node's key. The right subtree of a node contains only nodes with keys greater than the node's key. Both the left
and right subtrees must also be binary search trees.
Example 1:
Example 2:
Input: root = [5,1,4,null,null,3,6]
Output: false
Explanation: The root node's value is 5 but its right child's value is 4.
Constraints:
Approach
- Recursion
- for each node's val we check whether it's in the range (min, max)
- if it fails we return false
- recursively call left and right subtree
- start with (-infinity, +infinity)
- left child -> (min, node.val)
- right child -> (node.val, max)
Solution
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public boolean isValidBST(TreeNode root) {
Long min = Long.MIN_VALUE;
Long max = Long.MAX_VALUE;
Complexity Analysis
- Time Complexity: O(N)
- Space Complexity: O(H), H : height of tree, recursive calls
230. Kth Smallest Element in a BST
Medium
Given the root of a binary search tree, and an integer k, return the kth smallest value (1-indexed) of all the values of the nodes in the tree.
Example 1:
Example 2:
Constraints:
Follow up: If the BST is modified often (i.e., we can do insert and delete operations) and
you need to find the kth smallest frequently, how would you optimize?
Approach
- Recursion
- inorder traversal gives nodes in sorted order of a BST
- ans[] -> store the answer and k in the second index
- decrement ans[1] until it become 0
- when it become zero, that node is the ans
Solution
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public int kthSmallest(TreeNode root, int k) {
int[] ans = new int[2];
ans[1] = k;
inorder(root, ans);
return ans[0];
}
Complexity Analysis
- Time Complexity: O(N)
- Space Complexity: O(N)
Given two integer arrays preorder and inorder where preorder is the preorder traversal of a binary tree and inorder is the inorder traversal of the same tree, construct and return the
binary tree.
Example 1:
Input: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
Output: [3,9,20,null,null,15,7]
Example 2:
Constraints:
Approach
- start and end index
- inorderMap: mapping of inorder array with the index
- if start > end the return null
- root -> node with the preorder val with the preorder index
- root.left -> recursive call, in range (start, inorderMap.get(val)-1)
- root.right -> recursive call, in range (inorderMap.get(val)+1, end)
Solution
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
int preInd;
public TreeNode buildTree(int[] preorder, int[] inorder) {
preInd = 0;
int n = inorder.length;
int startIndex = 0, endIndex = n-1;
Map<Integer, Integer> inorderMap = new HashMap<>();
for(int i = 0; i < n; i++)
inorderMap.put(inorder[i], i);
return helper(preorder, inorder, startIndex, endIndex, inorderMap);
}
public TreeNode helper(int[] preorder, int[] inorder, int startIndex, int endIndex, Map<Integer, Integer> inorderMap) {
if(startIndex > endIndex)
return null;
int val = preorder[preInd++];
TreeNode root = new TreeNode(val);
root.left = helper(preorder, inorder, startIndex, inorderMap.get(val)-1, inorderMap);
root.right = helper(preorder, inorder, inorderMap.get(val)+1, endIndex, inorderMap);
return root;
}
}
Complexity Analysis
- Time Complexity: O(N)
- Space Complexity: O(N)
A path in a binary tree is a sequence of nodes where each pair of adjacent nodes in the sequence has an edge connecting them. A node can only appear in the sequence at most
once. Note that the path does not need to pass through the root.
The path sum of a path is the sum of the node's values in the path.
Given the root of a binary tree, return the maximum path sum of any non-empty path.
Example 1:
Input: root = [1,2,3]
Output: 6
Explanation: The optimal path is 2 -> 1 -> 3 with a path sum of 2 + 1 + 3 = 6.
Example 2:
Constraints:
Approach
- compare max at each node
- left call, right call
- compare max with node's val+left val, node's val+right val, node's val+left val+right val
- return max of node's val, node's val+left val, node's val+right val
Solution
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
int max;
public int maxPathSum(TreeNode root) {
max = -1001;
helper(root);
return max;
}
Complexity Analysis
- Time Complexity: O(n)
- Space Complexity: O(logn), recursive call stacks
Hard
Serialization is the process of converting a data structure or object into a sequence of bits so that it can be stored in a file or memory buffer, or transmitted across a network
connection link to be reconstructed later in the same or another computer environment.
Design an algorithm to serialize and deserialize a binary tree. There is no restriction on how your serialization/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.
Clarification: The input/output format is the same as how LeetCode serializes a binary tree. You do not necessarily need to follow this format, so please be creative and come up with
different approaches yourself.
Example 1:
Example 2:
Input: root = []
Output: []
Constraints:
Approach
Solution
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Codec {
return root;
}
}
// Your Codec object will be instantiated and called as such:
// Codec ser = new Codec();
// Codec deser = new Codec();
// TreeNode ans = deser.deserialize(ser.serialize(root));
Complexity Analysis
- Time Complexity: O(N)
- Space Complexity: O(N)
Tree
Patterns
BFS
DFS (Preorder, Inorder & Postorder)
BFS
Here are the steps of our algorithm:
Given the root of a binary tree, return the level order traversal of its nodes' values. (i.e., from left to right, level by level).
Example 1:
Example 2:
Example 3:
Input: root = []
Output: []
Constraints:
import java.util.*;
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) {
val = x;
}
};
class Main {
public static List<List<Integer>> traverse(TreeNode root) {
List<List<Integer>> result = new ArrayList<List<Integer>>();
if (root == null)
return result;
return result;
}
Time complexity
The time complexity of the above algorithm is O(N), where ‘N’ is the total number of nodes in the tree. This is due to the fact that we traverse each node once.
Space complexity
The space complexity of the above algorithm will be O(N) as we need to return a list containing the level order traversal. We will also need O(N) space for the queue. Since we can
have a maximum of N/2 nodes at any level (this could happen only at the lowest level), therefore we will need O(N) space to store them in the queue.
DFS
Inorder(tree)
import java.util.*;
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) {
val = x;
}
};
class Main {
public static void traverse(TreeNode root) {
if (root == null)
return;
traverse(root.left);
System.out.println(root.val);
traverse(root.right);
}
Time complexity
The time complexity of the above algorithm is O(N), where ‘N’ is the total number of nodes in the tree. This is due to the fact that we traverse each node once.
Space complexity
The space complexity of the above algorithm will be O(H) where H is the height of the tree, needed for recursive call stacks.
208. Implement Trie (Prefix Tree)
(https://leetcode.com/problems/implement-
trie-prefix-tree/)
Medium
A trie (pronounced as "try") or prefix tree is a tree data structure used to efficiently store and retrieve keys in a dataset of strings. There are various applications of this data structure,
such as autocomplete and spellchecker.
Example 1:
Input
["Trie", "insert", "search", "search", "startsWith", "insert", "search"]
[[], ["apple"], ["apple"], ["app"], ["app"], ["app"], ["app"]]
Output
[null, null, true, false, true, null, true]
Explanation
Trie trie = new Trie();
trie.insert("apple");
trie.search("apple"); // return True
trie.search("app"); // return False
trie.startsWith("app"); // return True
trie.insert("app");
trie.search("app"); // return True
Constraints:
At most 3 * 104 calls in total will be made to insert, search, and startsWith.
Approach
26 links, end marker
[ , , ...26]
/ . . . 26 \ /..26..\
Solution
class Trie {
TrieNode root;
public Trie() {
root = new TrieNode();
}
if(curr.node[ind] != null) {
curr = curr.node[ind];
} else {
curr.node[ind] = new TrieNode();
curr = curr.node[ind];
}
}
curr.end = true;
}
class TrieNode {
TrieNode[] node = new TrieNode[26];
boolean end;
}
/**
* Your Trie object will be instantiated and called as such:
* Trie obj = new Trie();
* obj.insert(word);
* boolean param_2 = obj.search(word);
* boolean param_3 = obj.startsWith(prefix);
*/
Complexity Analysis
- Time Complexity:
- insert: O(m), where m is the key length.
- search: O(m)
- startsWith: O(m)
- Space Complexity:
- insert: O(m)
- search: O(1)
- startsWith: O(1)
Design a data structure that supports adding new words and finding if a string matches any previously added string.
Example:
Input
["WordDictionary","addWord","addWord","addWord","search","search","search","search"]
[[],["bad"],["dad"],["mad"],["pad"],["bad"],[".ad"],["b.."]]
Output
[null,null,null,null,false,true,true,true]
Explanation
WordDictionary wordDictionary = new WordDictionary();
wordDictionary.addWord("bad");
wordDictionary.addWord("dad");
wordDictionary.addWord("mad");
wordDictionary.search("pad"); // return False
wordDictionary.search("bad"); // return True
wordDictionary.search(".ad"); // return True
wordDictionary.search("b.."); // return True
Constraints:
Approach
- Use Trie
Solution
class WordDictionary {
TrieNode root;
public WordDictionary() {
root = new TrieNode();
}
if (curr.node[ind] != null) {
curr = curr.node[ind];
} else {
curr.node[ind] = new TrieNode();
curr = curr.node[ind];
}
}
curr.end = true;
}
class TrieNode {
TrieNode[] node = new TrieNode[26];
boolean end;
}
}
/**
* Your WordDictionary object will be instantiated and called as such:
* WordDictionary obj = new WordDictionary();
* obj.addWord(word);
* boolean param_2 = obj.search(word);
*/
Complexity Analysis
- Time Complexity:
- Space Complexity:
Resources
703. Kth Largest Element in a Stream
Easy
Design a class to find the kth largest element in a stream. Note that it is the kth largest element in the sorted order, not the kth distinct element.
KthLargest(int k, int[] nums) Initializes the object with the integer k and the stream of integers nums.
int add(int val) Appends the integer val to the stream and returns the element representing the kth largest element in the stream.
Example 1:
Input
["KthLargest", "add", "add", "add", "add", "add"]
[[3, [4, 5, 8, 2]], [3], [5], [10], [9], [4]]
Output
[null, 4, 5, 5, 8, 8]
Explanation
Constraints:
while(pq.size() > k)
pq.poll();
}
return pq.peek();
}
}
/**
* Your KthLargest object will be instantiated and called as such:
* KthLargest obj = new KthLargest(k, nums);
* int param_1 = obj.add(val);
*/
You are given an array of integers stones where stones[i] is the weight of the ith stone.
We are playing a game with the stones. On each turn, we choose the heaviest two stones and smash them together. Suppose the heaviest two stones have weights x and y with x <=
y. The result of this smash is:
If x == y, both stones are destroyed, and If x != y, the stone of weight x is destroyed, and the stone of weight y has new weight y - x. At the end of the game, there is at most one stone
left.
Return the smallest possible weight of the left stone. If there are no stones left, return 0.
Example 1:
Example 2:
Constraints:
while(pq.size() > 1) {
int x = pq.poll();
int y = pq.poll();
if(x != y) {
pq.offer(x-y); // abs not rqd as x would always be greater than equal to y
}
}
return pq.isEmpty()?0:pq.peek();
}
}
Given an array of points where points[i] = [xi, yi] represents a point on the X-Y plane and an integer k, return the k closest points to the origin (0, 0).
The distance between two points on the X-Y plane is the Euclidean distance (i.e., √(x1 - x2)2 + (y1 - y2)2).
You may return the answer in any order. The answer is guaranteed to be unique (except for the order that it is in).
Example 1:
Example 2:
Constraints:
Approach
- Have a Max PriorityQueue based on euclidean distance
- add each point to PQ, if size > k then poll
- remaining points inside the PQ is the answer
Solution
class Solution {
public int[][] kClosest(int[][] points, int k) {
int[][] res = new int[k][2];
PriorityQueue<Point> pq = new PriorityQueue<Point>((a, b) -> new Double(b.dist).compareTo(new Double(a.dist)));
class Point {
int x;
int y;
double dist;
Point(int x, int y) {
this.x = x;
this.y = y;
dist = Math.pow(x*x + y*y, 0.5);
}
}
class Solution {
public int[][] kClosest(int[][] points, int k) {
int[][] res = new int[k][2];
PriorityQueue<int[]> pq = new PriorityQueue<int[]>((a, b) -> (b[0]*b[0] + b[1]*b[1]) - (a[0]*a[0] + a[1]*a[1]));
Complexity Analysis
- Time Complexity: O(nlogk) -> Adding to/removing from the heap (or priority queue)
only takes O(\log k) time when the size of the heap is capped at k elements.
- Space Complexity: O(k) -> The heap (or priority queue) will contain at most kk elements.
Given an integer array nums and an integer k, return the kth largest element in the array.
Note that it is the kth largest element in the sorted order, not the kth distinct element.
Example 1:
Example 2:
Constraints:
Approach
- Min PriorityQueue
- if size becomes > k, poll
- after going through the array, we'll have the kth largest element as the min element in the PQ
Solution
class Solution {
public int findKthLargest(int[] nums, int k) {
PriorityQueue<Integer> pq = new PriorityQueue<>((a,b)->a-b);
for(int num : nums) {
pq.offer(num);
if(pq.size() > k)
pq.poll();
}
return pq.peek();
}
}
Complexity Analysis
- Time Complexity: O(nlogk)
- Space Complexity: O(k)
TODO
Quick Select
Given a characters array tasks, representing the tasks a CPU needs to do, where each letter represents a different task. Tasks could be done in any order. Each task is done in one
unit of time. For each unit of time, the CPU could complete either one task or just be idle.
However, there is a non-negative integer n that represents the cooldown period between two same tasks (the same letter in the array), that is that there must be at least n units of
time between any two same tasks.
Return the least number of units of times that the CPU will take to finish all the given tasks.
Example 1:
Example 2:
Example 3:
Constraints:
Approach
Solution
class Solution {
public int leastInterval(char[] tasks, int n) {
int[] freq = new int[26];
int max = 0; // keep the max value
int maxCount = 0; // number of tasks with the max value
Complexity Analysis
- Time Complexity: O(N)
- Space Complexity: O(26)
The median is the middle value in an ordered integer list. If the size of the list is even, there is no middle value and the median is the mean of the two middle values.
For example, for arr = [2,3,4], the median is 3. For example, for arr = [2,3], the median is (2 + 3) / 2 = 2.5. Implement the MedianFinder class:
MedianFinder() initializes the MedianFinder object. void addNum(int num) adds the integer num from the data stream to the data structure. double findMedian() returns the median of
all elements so far. Answers within 10-5 of the actual answer will be accepted.
Example 1:
Input
["MedianFinder", "addNum", "addNum", "findMedian", "addNum", "findMedian"]
[[], [1], [2], [], [3], []]
Output
[null, null, null, 1.5, null, 2.0]
Explanation
MedianFinder medianFinder = new MedianFinder();
medianFinder.addNum(1); // arr = [1]
medianFinder.addNum(2); // arr = [1, 2]
medianFinder.findMedian(); // return 1.5 (i.e., (1 + 2) / 2)
medianFinder.addNum(3); // arr[1, 2, 3]
medianFinder.findMedian(); // return 2.0
Constraints:
Follow up:
If all integer numbers from the stream are in the range [0, 100], how would you optimize your solution?
If 99% of all integer numbers from the stream are in the range [0, 100], how would you optimize your solution?
Approach
- Use two heaps, one max heap(smallerList), other min heap(largerList)
- if smallList is not empty and first element is less than equal to num then add num to largeList
- else add num to smallList
- balance the size of both the heaps
- so that smallList never become more than 1 + size of largeList
- largeList's size always remain less or equal to the size of smallList
Solution
class MedianFinder {
int size;
PriorityQueue<Integer> smallList;
PriorityQueue<Integer> largeList;
public MedianFinder() {
smallList = new PriorityQueue<>(Collections.reverseOrder()); // maxHeap
largeList = new PriorityQueue<>(); // minHeap
}
if(size % 2 != 0) {
return (double) smallList.peek();
} else {
return (double) (smallList.peek() + largeList.peek())/2.0;
}
}
}
/**
* Your MedianFinder object will be instantiated and called as such:
* MedianFinder obj = new MedianFinder();
* obj.addNum(num);
* double param_2 = obj.findMedian();
*/
Complexity Analysis
- Time Complexity:
- add operation: O(logN)
- find median operation: O(1)
- Space Complexity:
- add operation: O(1)
- find median operation: O(1)
Resources
78. Subsets
(https://leetcode.com/problems/subsets/)
Medium
Given an integer array nums of unique elements, return all possible subsets (the power set).
The solution set must not contain duplicate subsets. Return the solution in any order.
Example 1:
Example 2:
Constraints:
Approach
Backtracking:
- Either select the element or not
- recursive call
tmp.add(nums[index]);
backtrack(nums, index+1, tmp, ans);
tmp.remove(tmp.size()-1);
backtrack(nums, index+1, tmp, ans);
Solution
class Solution {
public List<List<Integer>> subsets(int[] nums) {
List<Integer> tmp = new ArrayList<>();
List<List<Integer>> ans = new ArrayList<>();
backtrack(nums, 0, tmp, ans);
return ans;
}
private void backtrack(int[] nums, int index, List<Integer> tmp, List<List<Integer>> ans) {
if(index > nums.length)
return;
if(index == nums.length) {
ans.add(new ArrayList<>(tmp));
return;
}
tmp.add(nums[index]);
backtrack(nums, index+1, tmp, ans);
tmp.remove(tmp.size()-1);
backtrack(nums, index+1, tmp, ans);
}
}
Complexity Analysis
- Time Complexity: O(2^N)
- Space Complexity: O(N)
39. Combination Sum
(https://leetcode.com/problems/combination-
sum/)
Medium
Given an array of distinct integers candidates and a target integer target, return a list of all unique combinations of candidates where the chosen numbers sum to target. You may
return the combinations in any order.
The same number may be chosen from candidates an unlimited number of times. Two combinations are unique if the frequency of at least one of the chosen numbers is different.
It is guaranteed that the number of unique combinations that sum up to target is less than 150 combinations for the given input.
Example 1:
Example 2:
Example 3:
Constraints:
Approach
Backtrack:
- We can choose any of the element present in the array(n choices)
- In subsets, we have only 2 choices
- Looping through elements to create a n way recursive call
for(int i = index; i < nums.length; i++) {
tmp.add(nums[i]);
backtrack(nums, i, tmp, ans, target - nums[i]);
tmp.remove(tmp.size()-1);
}
Solution
class Solution {
public List<List<Integer>> combinationSum(int[] candidates, int target) {
List<List<Integer>> res = new ArrayList<>();
backtrack(candidates, 0, new ArrayList<>(), res, target);
return res;
}
private void backtrack(int[] nums, int index, List<Integer> tmp, List<List<Integer>> ans, int target) {
if(index >= nums.length || target < 0)
return;
if(target == 0) {
ans.add(new ArrayList<>(tmp));
return;
}
Complexity Analysis
- Time Complexity: O(N^N)
- Space Complexity: O(N)
46. Permutations
(https://leetcode.com/problems/permutations/)
Medium
Given an array nums of distinct integers, return all the possible permutations. You can return the answer in any order.
Example 1:
Example 2:
Example 3:
Constraints:
Approach
- we have n choices initially, after each selection we can't take that element again
- take a mark array to keep track of what elements fron the nums array which are already select in the current path
for(int i = 0; i < nums.length; i++) {
if(mark[i] == false) {
mark[i] = true;
tmp.add(nums[i]);
backtrack(nums, mark, tmp, ans);
tmp.remove(tmp.size()-1);
mark[i] = false;
}
}
Solution
class Solution {
public List<List<Integer>> permute(int[] nums) {
boolean[] mark = new boolean[nums.length];
List<List<Integer>> ans = new ArrayList<>();
backtrack(nums, mark, new ArrayList<>(), ans);
return ans;
}
private void backtrack(int[] nums, boolean[] mark, List<Integer> tmp, List<List<Integer>> ans) {
if(tmp.size() == nums.length) {
ans.add(new ArrayList<>(tmp));
return;
}
Complexity Analysis
- Time Complexity: O(N^N)
- Space Complexity: O(N)
90. Subsets II
(https://leetcode.com/problems/subsets-ii/)
Medium
Given an integer array nums that may contain duplicates, return all possible subsets (the power set).
The solution set must not contain duplicate subsets. Return the solution in any order.
Example 1:
Constraints:
Approach
Ref: 1.Subsets (https://github.com/dipjul/NeetCode-150/blob/13aea2145a56c73ef5e1b8ea0b5cbe94745415e9/10.%20Backtracking/1.Subsets.md)
Same as Subsets
- to skip duplicates, before making the 2nd backtracking call we check the current and next element
- while those are equal we keep skipping to the next index
Solution
class Solution {
public List<List<Integer>> subsetsWithDup(int[] nums) {
List<List<Integer>> ans = new ArrayList<>();
Arrays.sort(nums);
backtrack(nums, 0, new ArrayList<>(), ans);
return ans;
}
private void backtrack(int[] nums, int index, List<Integer> tmp, List<List<Integer>> ans) {
if(index > nums.length)
return;
if(index == nums.length) {
ans.add(new ArrayList<>(tmp));
return;
}
tmp.add(nums[index]);
backtrack(nums, index+1, tmp, ans);
tmp.remove(tmp.size()-1);
while(index+1 < nums.length && nums[index] == nums[index+1])
index++;
backtrack(nums, index+1, tmp, ans);
}
}
Complexity Analysis
- Time Complexity: O(2^N)
- Space Complexity: O(N)
Given a collection of candidate numbers (candidates) and a target number (target), find all unique combinations in candidates where the candidate numbers sum to target.
Each number in candidates may only be used once in the combination.
Example 1:
Example 2:
Constraints:
Approach
Ref: 2.Combination Sum (https://github.com/dipjul/NeetCode-150/blob/76226b171098f898f8263acd34b2d3236d30f471/10.%20Backtracking/2.CombinationSum.md)
Solution
class Solution {
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
List<List<Integer>> ans = new ArrayList<>();
Arrays.sort(candidates);
backtrack(candidates, 0, target, new ArrayList<>(), ans);
return ans;
}
private void backtrack(int[] nums, int index, int target, List<Integer> tmp, List<List<Integer>> ans) {
if(target == 0) {
ans.add(new ArrayList<>(tmp));
return;
}
if(index >= nums.length || target < 0)
return;
tmp.add(nums[index]);
backtrack(nums, index+1, target-nums[index], tmp, ans);
tmp.remove(tmp.size()-1);
while(index+1 < nums.length && nums[index] == nums[index+1])
index++;
backtrack(nums, index+1, target, tmp, ans);
}
}
Complexity Analysis
- Time Complexity: O(2^N)
- Space Complexity: O(N)
Given an m x n grid of characters board and a string word, return true if word exists in the grid.
The word can be constructed from letters of sequentially adjacent cells, where adjacent cells are horizontally or vertically neighboring. The same letter cell may not be used more than
once.
Example 1:
Example 2:
Example 3:
Constraints:
m == board.length
n = board[i].length
1 <= m, n <= 6
1 <= word.length <= 15
board and word consists of only lowercase and uppercase English letters.
Follow up: Could you use search pruning to make your solution faster with a larger board?
Approach
Backtracking:
- 4 choices top, down, left & right moves
- mark the element we are accessing
- if we match the word, we get the ans
Solution
class Solution {
public boolean exist(char[][] board, String word) {
boolean[] res = new boolean[1];
boolean[][] mark = new boolean[board.length][board[0].length];
for(int i = 0; i < board.length; i++) {
for(int j = 0; j < board[0].length; j++) {
if(board[i][j] == word.charAt(0)) {
backtrack(board, word, mark, i, j, res);
if(res[0] == true)
return true;
}
}
}
return false;
}
private void backtrack(char[][] board, String word, boolean[][] mark, int i, int j, boolean[] res) {
if (word.length() == 0) {
res[0] = true;
return;
}
if (i >= board.length || j >= board[0].length || i < 0 || j < 0 || mark[i][j])
return;
if (word.charAt(0) == board[i][j]) {
mark[i][j] = true;
if (i >= 0) {
backtrack(board, word.substring(1), mark, i - 1, j, res);
}
if (j >= 0) {
backtrack(board, word.substring(1), mark, i, j - 1, res);
}
if (i < board.length) {
backtrack(board, word.substring(1), mark, i + 1, j, res);
}
if (j < board[0].length) {
backtrack(board, word.substring(1), mark, i, j + 1, res);
}
mark[i][j] = false;
}
}
}
// little optimized
class Solution {
boolean[][] visited;
public boolean exist(char[][] board, String word) {
int rows = board.length;
int cols = board[0].length;
visited = new boolean[rows][cols];
public boolean search(int i, int j, int index, String word, char[][] board) {
if(index == word.length())
return true;
if(i < 0 || i >= board.length || j < 0 || j >= board[0].length || word.charAt(index) != board[i][j] || visited[i][j]) {
return false;
}
visited[i][j] = true;
if(
search(i+1, j, index+1, word, board) ||
search(i-1, j, index+1, word, board) ||
search(i, j+1, index+1, word, board) ||
search(i, j-1, index+1, word, board)
) {
return true;
}
visited[i][j] = false;
return false;
}
}
Complexity Analysis
- Time Complexity: O(4^N)
- Space Complexity: O(N)
Given a string s, partition s such that every substring of the partition is a palindrome. Return all possible palindrome partitioning of s.
Example 1:
Input: s = "aab"
Output: [["a","a","b"],["aa","b"]]
Example 2:
Input: s = "a"
Output: [["a"]]
Constraints:
Approach
- backtracking
- go through all possible combination of substring
- if the substring is palindrome add it to the tmp result and backtrack
- if substring becomes empty then add tmp result to the result
Solution
class Solution {
public List<List<String>> partition(String s) {
List<List<String>> result = new ArrayList();
helper(s, new ArrayList<String>(), result);
return result;
}
Complexity Analysis
- Time Complexity: O(N*2^N)
- Space Complexity: O(N)
Given a string containing digits from 2-9 inclusive, return all possible letter combinations that the number could represent. Return the answer in any order.
A mapping of digit to letters (just like on the telephone buttons) is given below. Note that 1 does not map to any letters.
Example 1:
Example 2:
Example 3:
Constraints:
Approach
Backtrack:
char chs[] = mp.get(str.charAt(i));
for(int j = 0; j < chs.length; j++) {
recursive(str, i+1, s+chs[j], res); - stmt
}
stmt is equivalent to:
String s = s+chs[j];
recursive(str, i+1, s, res);
s = s.substring(0,s.length()-1);
Solution
class Solution {
Map<Character, char[]> mp;
public List<String> letterCombinations(String digits) {
if(digits.equals(""))
return new ArrayList<>();
mp = new HashMap<>();
mp.put('2', new char[]{'a', 'b', 'c'});
mp.put('3', new char[]{'d', 'e', 'f'});
mp.put('4', new char[]{'g', 'h', 'i'});
mp.put('5', new char[]{'j', 'k', 'l'});
mp.put('6', new char[]{'m', 'n', 'o'});
mp.put('7', new char[]{'p', 'q', 'r', 's'});
mp.put('8', new char[]{'t', 'u', 'v'});
mp.put('9', new char[]{'w', 'x', 'y', 'z'});
List<String> res = new ArrayList<>();
recursive(digits, 0, "", res);
return res;
}
}
}
Complexity Analysis
- Time Complexity:
- Space Complexity:
51. N-Queens
(https://leetcode.com/problems/n-queens/)
Hard
The n-queens puzzle is the problem of placing n queens on an n x n chessboard such that no two queens attack each other.
Given an integer n, return all distinct solutions to the n-queens puzzle. You may return the answer in any order.
Each solution contains a distinct board configuration of the n-queens' placement, where 'Q' and '.' both indicate a queen and an empty space, respectively.
Example 1:
Input: n = 4
Output: [[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]]
Explanation: There exist two distinct solutions to the 4-queens puzzle as shown above
Example 2:
Input: n = 1
Output: [["Q"]]
Constraints:
1 <= n <= 9
Approach
- Backtracking
- Used 3 boolean arrays to mark row, left diagonal and rightdiagonal
- r-c could be -ve so we add the n-1 to it
- for each column,
- we go through each row and check whether we can place the queen or not
- if possible then we place the column index at the row[]
- recursive call to next column
Solution
// Do not try this at home
class Solution {
int[] row;
boolean[] rw, ld, rd;
public List<List<String>> solveNQueens(int n) {
row = new int[n];
rw = new boolean[n];
ld = new boolean[2*n-1];
rd = new boolean[2*n-1];
List<List<String>> ans = new ArrayList<>();
backtrack(0, n, ans);
return ans;
}
Complexity Analysis
- Time Complexity: O(n!)
- Space Complexity: O(n^2), building the result
Resources
200. Number of Islands
(https://leetcode.com/problems/number-of-
islands/)
Medium
Given an m x n 2D binary grid grid which represents a map of '1's (land) and '0's (water), return 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 the grid are all surrounded by water.
Example 1:
Input: grid = [
["1","1","1","1","0"],
["1","1","0","1","0"],
["1","1","0","0","0"],
["0","0","0","0","0"]
]
Output: 1
Example 2:
Input: grid = [
["1","1","0","0","0"],
["1","1","0","0","0"],
["0","0","1","0","0"],
["0","0","0","1","1"]
]
Output: 3
Constraints:
m == grid.length
n == grid[i].length
1 <= m, n <= 300
grid[i][j] is '0' or '1'.
Approach
- DFS
- number of time DFS called is the ans
Soluiton
class Solution {
public int numIslands(char[][] grid) {
boolean[][] mark = new boolean[grid.length][grid[0].length];
int res = 0;
for(int i = 0; i < grid.length; i++) {
for(int j = 0; j < grid[0].length; j++) {
if(!mark[i][j] && grid[i][j] == '1') {
res++;
dfs(grid, i, j, mark);
}
}
}
return res;
}
Complexity Analysis
- Time Complexity: O(n*m)
- Space Complexity: O(n*m)
Each node in the graph contains a value (int) and a list (List[Node]) of its neighbors.
class Node {
public int val;
public List<Node> neighbors;
}
For simplicity, each node's value is the same as the node's index (1-indexed). For example, the first node with val == 1, the second node with val == 2, and so on. The graph is
represented in the test case using an adjacency list.
An adjacency list is a collection of unordered lists used to represent a finite graph. Each list describes the set of neighbors of a node in the graph.
The given node will always be the first node with val = 1. You must return the copy of the given node as a reference to the cloned graph.
Example 1:
Input: adjList = [[2,4],[1,3],[2,4],[1,3]]
Output: [[2,4],[1,3],[2,4],[1,3]]
Explanation: There are 4 nodes in the graph.
1st node (val = 1)'s neighbors are 2nd node (val = 2) and 4th node (val = 4).
2nd node (val = 2)'s neighbors are 1st node (val = 1) and 3rd node (val = 3).
3rd node (val = 3)'s neighbors are 2nd node (val = 2) and 4th node (val = 4).
4th node (val = 4)'s neighbors are 1st node (val = 1) and 3rd node (val = 3).
Example 2:
Example 3:
Input: adjList = []
Output: []
Explanation: This an empty graph, it does not have any nodes.
Constraints:
Approach
Solution
/*
// Definition for a Node.
class Node {
public int val;
public List<Node> neighbors;
public Node() {
val = 0;
neighbors = new ArrayList<Node>();
}
public Node(int _val) {
val = _val;
neighbors = new ArrayList<Node>();
}
public Node(int _val, ArrayList<Node> _neighbors) {
val = _val;
neighbors = _neighbors;
}
}
*/
class Solution {
while (!q.isEmpty()) {
Node curr = q.poll();
set.add(curr);
return mp.get(node.val);
}
}
Complexity Analysis
- Time Complexity: O(n*m)
- Space Complexity: O(n+m)
You are given an m x n binary matrix grid. An island is a group of 1's (representing land) connected 4-directionally (horizontal or vertical.) You may assume all four edges of the grid
are surrounded by water.
The area of an island is the number of cells with a value 1 in the island.
Example 1:
Input: grid = [
[0,0,1,0,0,0,0,1,0,0,0,0,0],
[0,0,0,0,0,0,0,1,1,1,0,0,0],
[0,1,1,0,1,0,0,0,0,0,0,0,0],
[0,1,0,0,1,1,0,0,1,0,1,0,0],
[0,1,0,0,1,1,0,0,1,1,1,0,0],
[0,0,0,0,0,0,0,0,0,0,1,0,0],
[0,0,0,0,0,0,0,1,1,1,0,0,0],
[0,0,0,0,0,0,0,1,1,0,0,0,0]]
Output: 6
Explanation: The answer is not 11, because the island must be connected 4-directionally.
Example 2:
Constraints:
m == grid.length
n == grid[i].length
1 <= m, n <= 50
grid[i][j] is either 0 or 1.
Approach
- DFS
- count number of dfs call inside
Solution
class Solution {
public int maxAreaOfIsland(int[][] grid) {
boolean[][] mark = new boolean[grid.length][grid[0].length];
int res = 0;
Complexity Analysis
- Time Complexity: O(n*m)
- Space Complexity: O(n*m)
There is an m x n rectangular island that borders both the Pacific Ocean and Atlantic Ocean. The Pacific Ocean touches the island's left and top edges, and the Atlantic Ocean
touches the island's right and bottom edges.
The island is partitioned into a grid of square cells. You are given an m x n integer matrix heights where heights[r][c] represents the height above sea level of the cell at coordinate (r,
c).
The island receives a lot of rain, and the rain water can flow to neighboring cells directly north, south, east, and west if the neighboring cell's height is less than or equal to the current
cell's height. Water can flow from any cell adjacent to an ocean into the ocean.
Return a 2D list of grid coordinates result where result[i] = [ri, ci] denotes that rain water can flow from cell (ri, ci) to both the Pacific and Atlantic oceans.
Example 1:
Example 2:
Constraints:
m == heights.length
n == heights[r].length
1 <= m, n <= 200
0 <= heights[r][c] <= 105
Approach
- dfs: start from all the boundary along with respective set for pacific and atlantic
- intersection of both set
Solution
class Solution {
private void dfs(int[][] grid, int i, int j, Set<String> visited, int prev) {
if (i < 0 || j < 0 || i >= grid.length || j >= grid[0].length || grid[i][j] < prev || visited.contains(i + "," + j)) return;
Complexity Analysis
- Time Complexity: O(m*n)
- Space Complexity: O(m*n)
Given an m x n matrix board containing 'X' and 'O', capture all regions that are 4-directionally surrounded by 'X'.
A region is captured by flipping all 'O's into 'X's in that surrounded region.
Example 1:
Input: board = [
["X","X","X","X"],
["X","O","O","X"],
["X","X","O","X"],
["X","O","X","X"]]
Output: [
["X","X","X","X"],
["X","X","X","X"],
["X","X","X","X"],
["X","O","X","X"]]
Explanation: Surrounded regions should not be on the border, which means that any 'O' on the border of the board are not flipped to
Example 2:
Constraints:
m == board.length
n == board[i].length
1 <= m, n <= 200
board[i][j] is 'X' or 'O'.
Approach
- start dfs from all the boundaries
- mark all the cells that can be reach from the dfs as 1
- all those which were not marked 1 and in give board is "0", set them "X"
Solution
class Solution {
public void solve(char[][] board) {
int[][] mark = new int[board.length][board[0].length];
for (int j = 0; j < board[0].length; j++) {
if (board[0][j] == 'O')
dfs(board, 0, j, mark);
}
for (int j = 0; j < board[0].length; j++) {
if (board[board.length - 1][j] == 'O')
dfs(board, board.length - 1, j, mark);
}
for (int j = 0; j < board.length; j++) {
if (board[j][0] == 'O')
dfs(board, j, 0, mark);
}
for (int j = 0; j < board.length; j++) {
if (board[j][board[0].length - 1] == 'O')
dfs(board, j, board[0].length - 1, mark);
}
for(int i = 0; i < board.length; i++) {
for(int j = 0; j < board[0].length; j++) {
if(mark[i][j] == 0 && board[i][j] == 'O')
board[i][j] = 'X';
}
}
}
Complexity Analysis
- Time Complexity: O(m*n)
- Space Complexity: O(m*n)
You are given an m x n grid where each cell can have one of three values:
Every minute, any fresh orange that is 4-directionally adjacent to a rotten orange becomes rotten.
Return the minimum number of minutes that must elapse until no cell has a fresh orange. If this is impossible, return -1.
Example 1:
Example 2:
Example 3:
Constraints:
m == grid.length
n == grid[i].length
1 <= m, n <= 10
grid[i][j] is 0, 1, or 2.
Approaches
- Implementation of Topological Sort
- Insert all the rotten tomatoes inside the queue as sources
- have an fresh tomato count
- while sources queue not empty,
- we pull one pos at a time and check it's neighbour if there is any fresh tomato
- if we found fresh tomato, we make it rotten and add to our sources queue, decrement the fresh count
- for each run of while loop,
- we check if the sources is not empty, increment the time
Solution
class Solution {
public int orangesRotting(int[][] grid) {
int[][] dirs = {{-1, 0}, {1, 0}, {0, -1}, {0, 1} };
Queue<int[]> q = new LinkedList<>();
int n = grid.length, m = grid[0].length;
int countFresh = 0;
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++) {
if(grid[i][j] == 1)
countFresh++;
if(grid[i][j] == 2)
q.offer(new int[]{i, j});
}
}
if(countFresh == 0) return 0;
int time = 0;
while(!q.isEmpty()) {
int size = q.size();
for(int i = 0; i < size; i++) {
int[] currPos = q.poll();
int currI = currPos[0], currJ = currPos[1];
for(int[] dir : dirs) {
if(currI+dir[0] < 0 || currJ+dir[1] < 0 || currI+dir[0] >= n || currJ+dir[1] >= m || grid[currI+dir[0]][currJ+dir
continue;
if(grid[currI+dir[0]][currJ+dir[1]] == 1) {
grid[currI+dir[0]][currJ+dir[1]] = 2;
q.offer(new int[]{currI+dir[0], currJ+dir[1]});
countFresh--;
}
}
}
if(!q.isEmpty())
time++;
}
return countFresh!=0?-1:time;
}
}
Complexity Analysis
- Time Complexity: O(n*m)
- Space Complexity: O(n*m)
Description You are given a m x n 2D grid initialized with these three possible values.
-1 : A wall or an obstacle.
0 : A gate.
INF - Infinity means an empty room. We use the value 2^31 - 1 = 2147483647 to represent INF as you may assume that the distance to a gate is less than 2147483647.
Fill each empty room with the distance to its nearest gate. If it is impossible to reach a Gate, that room should remain filled with INF
Example 1
Input:
[
[2147483647,-1,0,2147483647],
[2147483647,2147483647,2147483647,-1],
[2147483647,-1,2147483647,-1],
[0,-1,2147483647,2147483647]]
Output:
[
[3,-1,0,1],
[2,2,1,-1],
[1,-1,2,-1],
[0,-1,3,4]]
Explanation:
the 2D grid is:
INF -1 0 INF
INF INF INF -1
INF -1 INF -1
0 -1 INF INF
the answer is:
3 -1 0 1
2 2 1 -1
1 -1 2 -1
0 -1 3 4
Example 2
Input:
[
[0,-1],
[2147483647,2147483647]]
Output:
[
[0,-1],
[1,2]]
Tags
Company
Facebook
Google
Approach
- BFS or Topological Sort
- Start from the grid having 0 (add them to a queue)
- while queue is not empty:
- if neighbour of current position is INF, change it to 1+val coming from the queue and add it to queue
- otherwise take min of neighour's value and 1+val
Solution
public class Solution {
/**
* @param rooms: m x n 2D grid
* @return: nothing
*/
public void wallsAndGates(int[][] grid) {
int[][] dirs = {{-1, 0}, {1, 0}, {0, -1}, {0, 1} };
Queue<int[]> q = new LinkedList<>();
int n = grid.length, m = grid[0].length;
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++) {
if(grid[i][j] == 0)
q.offer(new int[]{i, j});
}
}
while (!q.isEmpty()) {
int size = q.size();
for (int i = 0; i < size; i++) {
int[] currPos = q.poll();
int currI = currPos[0], currJ = currPos[1];
int val = grid[currI][currJ];
for (int[] dir : dirs) {
if (currI + dir[0] < 0 || currJ + dir[1] < 0 || currI + dir[0] >= n || currJ + dir[1] >= m
|| grid[currI + dir[0]][currJ + dir[1]] == -1)
continue;
else if (grid[currI + dir[0]][currJ + dir[1]] == 2147483647) {
grid[currI + dir[0]][currJ + dir[1]] = 1 + val;
q.offer(new int[] { currI + dir[0], currJ + dir[1] });
} else {
grid[currI + dir[0]][currJ + dir[1]] = Math.min(grid[currI + dir[0]][currJ + dir[1]], 1 + val);
}
}
}
}
}
}
Complexity Analysis
- Time Complexity: O(k*n*m)
- Space Complexity: O(n*m)
There are a total of numCourses courses you have to take, labeled from 0 to numCourses - 1. You are given an array prerequisites where prerequisites[i] = [ai, bi] indicates that you
must take course bi first if you want to take course ai.
For example, the pair [0, 1], indicates that to take course 0 you have to first take course 1. Return true if you can finish all courses. Otherwise, return false.
Example 1:
Input: numCourses = 2, prerequisites = [[1,0]]
Output: true
Explanation: There are a total of 2 courses to take.
To take course 1 you should have finished course 0. So it is possible.
Example 2:
Constraints:
Approach
Topological Sort
- Have look a the solution for understanding the Topological sort algorithm
Solution
class Solution {
public boolean canFinish(int numCourses, int[][] prerequisites) {
// List<Integer> result = new ArrayList<>();
int result = 0;
// 4. For each source, add it to the result, subtract 1 from all of it's children's in-degree
// & add if any child has in-degree 0, add it to sources queue
while(!sources.isEmpty()) {
int vertex = sources.poll();
result++;
for(int child:graph.get(vertex)) {
inDegree.put(child, inDegree.get(child)-1);
if(inDegree.get(child) == 0)
sources.offer(child);
}
}
// 5. If size of result equal to numCourses then return true else return false
return result == numCourses;
}
}
Complexity Analysis
- Time Complexity: O(m*n)
- Space Complexity: O(m*n)
There are a total of numCourses courses you have to take, labeled from 0 to numCourses - 1. You are given an array prerequisites where prerequisites[i] = [ai, bi] indicates that you
must take course bi first if you want to take course ai.
For example, the pair [0, 1], indicates that to take course 0 you have to first take course 1. Return the ordering of courses you should take to finish all courses. If there are many valid
answers, return any of them. If it is impossible to finish all courses, return an empty array.
Example 1:
Example 2:
Example 3:
Constraints:
Aprroach
Ref: 8. Course Schedule (https://github.com/dipjul/NeetCode-150/blob/1db1597fe0d82d4741ecd5ee3600aea518824bb1/11.%20Graphs/8.CourseSchedule.md)
Topologicalo Sort
Solution
class Solution {
public int[] findOrder(int numCourses, int[][] prerequisites) {
List<Integer> result = new ArrayList<>();
// 4. For each source, add it to the result, subtract 1 from all of it's children's in-degree
// & add if any child has in-degree 0, add it to sources queue
while(!sources.isEmpty()) {
int vertex = sources.poll();
result.add(vertex);
for(int child:graph.get(vertex)) {
inDegree.put(child, inDegree.get(child)-1);
if(inDegree.get(child) == 0)
sources.offer(child);
}
}
if(result.size() != numCourses)
return new int[]{};
return result.stream().mapToInt(i->i).toArray();
}
}
Complexity Analysis
- Time Complexity: O(n*m)
- Space Complexity: O(n*m)
In this problem, a tree is an undirected graph that is connected and has no cycles.
You are given a graph that started as a tree with n nodes labeled from 1 to n, with one additional edge added. The added edge has two different vertices chosen from 1 to n, and was
not an edge that already existed. The graph is represented as an array edges of length n where edges[i] = [ai, bi] indicates that there is an edge between nodes ai and bi in the graph.
Return an edge that can be removed so that the resulting graph is a tree of n nodes. If there are multiple answers, return the answer that occurs last in the input.
Example 1:
Example 2:
Constraints:
n == edges.length
3 <= n <= 1000
edges[i].length == 2
1 <= ai < bi <= edges.length
ai != bi
There are no repeated edges.
The given graph is connected.
Approach
Ref: Union Find (https://github.com/dipjul/NeetCode-150/blob/e7002953ae531e571f4d148f591a265dda256d7d/Algorithms/1.UnionFind.md)
- Using UnionFind we'll check whether the nodes of the given edge are already connected without using the current edge
- if already connect which means this edge is reduntant
- else union the nodes of the current edge
Solution
class Solution {
int[] parent;
int[] rank;
public int[] findRedundantConnection(int[][] edges) {
int n = edges.length;
init(n);
int[] res = new int[2];
for(int[] edge:edges) {
if(!union(edge[0], edge[1]))
res = new int[]{ edge[0], edge[1] };
}
return res;
}
Complexity Analysis
- Time Complexity: O(n)
- Space Complexity: O(n)
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 to find the number of connected components in an undirected
graph.
Example 1:
0 3
| |
1 --- 2 4
Output: 2
Example 2:
Input: n = 5 and edges = [[0, 1], [1, 2], [2, 3], [3, 4]]
0 4
| |
1 --- 2 --- 3
Output: 1
Note: You can assume that no duplicate edges will appear in edges. Since all edges are undirected, [0, 1] is the same as [1, 0] and thus will not appear together in edges.
Approach
1. DFS
- Number of times dfs called is equal to the number of components
2. Union Find
- Take number of nodes as the number of components initially
- if the nodes of an edge are not already connected then decrease the count and union the nodes
Solution
// 1. DFS
class Solution {
public int countComponents(int n, int[][] edges) {
HashMap<Integer, List<Integer>> graph = new HashMap<Integer, List<Integer>>();
boolean[] visited = new boolean[n];
int count = 0;
// Step - 1 Build the graph
for(int i = 0; i < n; i++) {
graph.put(i, new ArrayList<Integer>());
}
UnionFind(int size) {
root = new int[size];
rank = new int[size];
if(rootX != rootY) {
if(rank[rootX] > rank[rootY])
root[rootY] = rootX;
else if(rank[rootX] < rank[rootY])
root[rootX] = rootY;
else {
root[rootY] = rootX;
rank[rootX]++;
}
}
}
Complexity Analysis
- Time Complexity:
- DFS: O(n)
- Union Find: O(n)
- Space Complexity:
- DFS: O(n+m)
- Union Find: O(n)
178 · Graph Valid Tree
(https://www.lintcode.com/problem/178/)
Medium
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 to check whether these edges make up a valid tree.
You can assume that no duplicate edges will appear in edges. Since all edges are undirected, [0, 1] is the same as [1, 0] and thus will not appear together in edges.
Example 1:
Input: n = 5 edges = [[0, 1], [0, 2], [0, 3], [1, 4]]
Output: true.
Example 2:
Input: n = 5 edges = [[0, 1], [1, 2], [2, 3], [1, 3], [1, 4]]
Output: false.
Approach
- check if number of edges is equal to n-1 or not
- if not equal return false;
- do dfs and put it in a set, size of set should be equal to number of nodes
Solution
public class Solution {
/**
* @param n: An integer
* @param edges: a list of undirected edges
* @return: true if it's a valid tree, or false
*/
public boolean validTree(int n, int[][] edges) {
// write your code here
if(edges.length != n-1)
return false;
if(n == 0 || n == 1)
return true;
Set<Integer> mark = new HashSet<>();
Map<Integer, List<Integer>> graph = new HashMap<>();
Complexity Analysis
- Time Complexity: O(n*m)
- Space Complexity: O(n+m)
A transformation sequence from word beginWord to word endWord using a dictionary wordList is a sequence of words beginWord -> s1 -> s2 -> ... -> sk such that:
Given two words, beginWord and endWord, and a dictionary wordList, return the number of words in the shortest transformation sequence from beginWord to endWord, or 0 if no
such sequence exists.
Example 1:
Input: beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log","cog"]
Output: 5
Explanation: One shortest transformation sequence is "hit" -> "hot" -> "dot" -> "dog" -> cog", which is 5 words long.
Example 2:
Constraints:
Approach
- Add the begin word to the wordList
- Create a graph such that neighbours of each node is differ by one character
- eg. fog would be neighbour of cog
- if endWord not present in the graph return 0
- How to find if two words are neighbour?
- Loop through the two words, whenever it differs increment the count
- if count == 1 return true else false
- Start bfs search from the beginWord untill we reach the endWord
- Keep count of distance from beginWord, return distance
Solution
class Solution {
if (!graph.containsKey(endWord)) return 0;
q.offer(beginWord);
if (q.size() == 0) return 0;
Set<String> visited = new HashSet<>();
int pathSize = 0;
while (!q.isEmpty()) {
int size = q.size();
pathSize++;
for (int i = 0; i < size; i++) {
String s1 = q.poll();
visited.add(s1);
if (s1.equals(endWord)) return pathSize;
for (String s : graph.get(s1)) {
if (!visited.contains(s)) q.offer(s);
}
}
}
return 0;
}
Complexity Analysis
- Time Complexity: O(n*n)
- Space Complexity: O(n+m)
Resources
1584. Min Cost to Connect All Points
(https://leetcode.com/problems/min-cost-to-
connect-all-points/)
Medium
You are given an array points representing integer coordinates of some points on a 2D-plane, where points[i] = [xi, yi].
The cost of connecting two points [xi, yi] and [xj, yj] is the manhattan distance between them: |xi - xj| + |yi - yj|, where |val| denotes the absolute value of val.
Return the minimum cost to make all points connected. All points are connected if there is exactly one simple path between any two points.
Example 1:
We can connect the points as shown above to get the minimum cost of 20.
Notice that there is a unique path between every pair of points.
Example 2:
Constraints:
1 <= points.length <= 1000 -106 <= xi, yi <= 106 All pairs (xi, yi) are distinct.
Approach
- MST
- PRIMS Algorithm
Solution
class Solution {
class Edge {
int[] x;
int[] y;
int cost;
Edge(int[] x, int[] y) {
this.x = x;
this.y = y;
this.cost = Math.abs(x[0]-y[0])+Math.abs(x[1]-y[1]);
}
}
// to detect cycle
private boolean detectCycle(int[] a, int[] b, Set<int[]> set) {
return set.contains(a) && set.contains(b);
}
}
Complexity Analysis
- Time Complexity: O(V*E)
- Space Complexity: O(V+E)
You are given a network of n nodes, labeled from 1 to n. You are also given times, a list of travel times as directed edges times[i] = (ui, vi, wi), where ui is the source node, vi is the
target node, and wi is the time it takes for a signal to travel from source to target.
We will send a signal from a given node k. Return the minimum time it takes for all the n nodes to receive the signal. If it is impossible for all the n nodes to receive the signal, return
-1.
Example 1:
Example 2:
Example 3:
Constraints:
Approach
Solution
public class Solution {
Complexity Analysis
- Time Complexity:
- Space Complexity:
There are n cities connected by some number of flights. You are given an array flights where flights[i] = [fromi, toi, pricei] indicates that there is a flight from city fromi to city toi with
cost pricei.
You are also given three integers src, dst, and k, return the cheapest price from src to dst with at most k stops. If there is no such route, return -1.
Example 1:
Input: n = 4, flights = [[0,1,100],[1,2,100],[2,0,100],[1,3,600],[2,3,200]], src = 0, dst = 3, k = 1
Output: 700
Explanation:
The graph is shown above.
The optimal path with at most 1 stop from city 0 to 3 is marked in red and has cost 100 + 600 = 700.
Note that the path through cities [0,1,2,3] is cheaper but is invalid because it uses 2 stops.
Example 2:
Example 3:
Constraints:
Approach
Ref: Bellman Ford (https://github.com/dipjul/NeetCode-
150/blob/9a8121cc3db395bc2b180b56c88524c678b72d03/Algorithms/4.Bellman-ford.md)
Solution
class Solution {
public int findCheapestPrice(int n, int[][] flights, int src, int dst, int k) {
int[] cost = new int[n];
Arrays.fill(cost, Integer.MAX_VALUE);
int[] tmp = new int[n];
Arrays.fill(tmp, Integer.MAX_VALUE);
cost[src] = 0;
tmp[src] = 0;
while(k >= 0) {
for(int[] flight : flights) {
if(cost[flight[0]] != Integer.MAX_VALUE) {
int newCost = cost[flight[0]]+flight[2];
if(newCost < tmp[flight[1]])
tmp[flight[1]] = newCost;
}
}
cost = Arrays.copyOfRange(tmp, 0, n);
k--;
}
return cost[dst] == Integer.MAX_VALUE?-1:cost[dst];
}
}
Complexity Analysis
- Time Complexity: O(k*E), E size of flights array
- Space Complexity: O(n)
Resources
70. Climbing Stairs
(https://leetcode.com/problems/climbing-
stairs/)
Easy
Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top?
Example 1:
Input: n = 2
Output: 2
Explanation: There are two ways to climb to the top.
1. 1 step + 1 step
2. 2 steps
Example 2:
Input: n = 3
Output: 3
Explanation: There are three ways to climb to the top.
1. 1 step + 1 step + 1 step
2. 1 step + 2 steps
3. 2 steps + 1 step
Constraints:
1 <= n <= 45
Approach
- Problem effectively becomes fibonacci
Solution
class Solution {
public int climbStairs(int n) {
int one = 1, two = 1;
for(int i = 2; i <= n; i++) {
int tmp = one;
one = one + two;
two = tmp;
}
return one;
}
}
Complexity Analysis
- Time Complexity: O(N)
- Space Complexity: O(1)
You are given an integer array cost where cost[i] is the cost of ith step on a staircase. Once you pay the cost, you can either climb one or two steps.
You can either start from the step with index 0, or the step with index 1.
Example 1:
Example 2:
Input: cost = [1,100,1,1,1,100,1,1,100,1]
Output: 6
Explanation: You will start at index 0.
- Pay 1 and climb two steps to reach index 2.
- Pay 1 and climb two steps to reach index 4.
- Pay 1 and climb two steps to reach index 6.
- Pay 1 and climb one step to reach index 7.
- Pay 1 and climb two steps to reach index 9.
- Pay 1 and climb one step to reach the top.
The total cost is 6.
Constraints:
Approach
- Start from the end of the array
- Recursive formula:
- cost[i] = cost[i] + min(cost[i+1], cost[i+2])
- return min(cost[o], cost[1])
Solution
class Solution {
public int minCostClimbingStairs(int[] cost) {
Complexity Analysis
- Time Complexity: O(N)
- Space Complexity O(1)
You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed, the only constraint stopping you from robbing each of them
is that adjacent houses have security systems connected and it will automatically contact the police if two adjacent houses were broken into on the same night.
Given an integer array nums representing the amount of money of each house, return the maximum amount of money you can rob tonight without alerting the police.
Example 1:
Input: nums = [1,2,3,1]
Output: 4
Explanation: Rob house 1 (money = 1) and then rob house 3 (money = 3).
Total amount you can rob = 1 + 3 = 4.
Example 2:
Constraints:
Approach
Pattern:
for loop
dp[i] = max(dp[i-1], nums[i]+dp[i-2]);
- either take the amount till previous element or else add current element to the amount till pre previous elements
Solution
class Solution {
public int rob(int[] nums) {
int n = nums.length;
if(n == 1)
return nums[0];
int[] dp = new int[n];
dp[0] = nums[0];
dp[1] = Math.max(nums[0], nums[1]);
for(int i = 2; i < n; i++) {
dp[i] = Math.max(dp[i-1], nums[i]+dp[i-2]);
}
return dp[n-1];
}
// optimized
class Solution {
public int rob(int[] nums) {
int n = nums.length;
if(n == 1)
return nums[0];
int prev2 = nums[0];
int prev1 = Math.max(nums[0], nums[1]);
You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed. All houses at this place are arranged in a circle. That
means the first house is the neighbor of the last one. Meanwhile, adjacent houses have a security system connected, and it will automatically contact the police if two adjacent houses
were broken into on the same night.
Given an integer array nums representing the amount of money of each house, return the maximum amount of money you can rob tonight without alerting the police.
Example 1:
Example 2:
Example 3:
Constraints:
Approach
Reference: 3. House Robber (https://github.com/dipjul/NeetCode-150/blob/d95d91ca2c7e0e25f421e3959ce0c0b62d9ba5a0/13.%201-
D%20Dynamic%20Programming/3.HouseRobber.md)
- Reuse house robber, 1st time for [0, n-1] & 2nd time for [1, n]
- Return max out of them
Solution
class Solution {
public int rob(int[] nums) {
int n = nums.length;
if(n == 1)
return nums[0];
if(n == 2)
return Math.max(nums[0], nums[1]);
int prev2 = nums[0];
int prev1 = Math.max(nums[0], nums[1]);
Complexity Analysis
- Time Complexity: O(2 * N) ~ O(N)
- Space Complexity: O(1)
Example 1:
Input: s = "babad"
Output: "bab"
Explanation: "aba" is also a valid answer.
Example 2:
Input: s = "cbbd"
Output: "bb"
Constraints:
Approach
Approach 1:
- for each index, try to find odd length & even length palindromes
- odd: start the inner loop from the same index
- even: start the inner loop one pointer on i and other at i+1
- expand towards the left and right of i while the chars are same
- keep checking the len, and store the start and end
- substring(start,end+1), end+1 because the substring method takes end index one more than the original end index
Approach 2:
- Manacher Algorithm
Solution
class Solution {
public String longestPalindrome(String s) {
int resLen = 0, start = 0, end = 0;
class Solution {
public String longestPalindrome(String s) {
StringBuilder sb = new StringBuilder();
// appending chars before, inbetween and end to make the string
// such that we can use the manacher odd algorithm
sb.append("$");
for(int i = 0; i < s.length(); i++) {
sb.append("#");
sb.append(s.charAt(i));
}
sb.append("#");
sb.append("&");
int[] p = manacher_odd(sb.toString());
int center = 0, resLen = 0;
for(int i = 0; i < p.length; i++) {
if(p[i] > resLen) {
center = i;
resLen = p[i];
}
}
Complexity Analysis
- Time Complexity:
- Approach 1: O(N*N)
- Approach 2: O(N)
- Space Complexity:
- Approach 1: O(1)
- Approach 2: O(N)
Example 1:
Input: s = "abc"
Output: 3
Explanation: Three palindromic strings: "a", "b", "c".
Example 2:
Input: s = "aaa"
Output: 6
Explanation: Six palindromic strings: "a", "a", "a", "aa", "aa", "aaa".
Constraints:
Approach
Reference: 5.LongestPalindromicSubstring (https://github.com/dipjul/NeetCode-150/blob/7961198c07e09a081fec9fbcc445e315bab042a7/13.%201-
D%20Dynamic%20Programming/5.LongestPalindromicSubstring.md)
Approach 1:
- expand around every element as a center
- ood length (i,i)
- even length (i,i+1)
- increment for each match
Approach 2:
- Manacher Algorithm
- every element in p[i]
- (p[i]+1)/2
Solution
class Solution {
public int countSubStrings(String s) {
if (s.length() < 2) {
return s.length();
}
int result = 0;
for (int i = 0; i < s.length(); i++) {
// Odd Length
int left = i, right = i;
while (left >=0 && right < s.length() && s.charAt(left) == s.charAt(right)) {
result++;
left -=1;
right +=1;
}
// Even Length
left = i;
right = i + 1;
while (left >=0 && right < s.length() && s.charAt(left) == s.charAt(right)) {
result++;
left -=1;
right +=1;
}
}
return result;
}
}
class Solution {
public int countSubstrings(String s) {
StringBuilder sb = new StringBuilder();
sb.append("$");
for(int i = 0; i < s.length(); i++) {
sb.append("#");
sb.append(s.charAt(i));
}
sb.append("#");
sb.append("@");
int[] p = manacher_odd(sb.toString());
int ans = 0;
for(int i = 0; i < p.length; i++)
ans += (p[i]+1)/2;
return ans;
}
while(s.charAt(i-(p[i]+1)) == s.charAt(i+(p[i]+1)))
p[i]++;
return p;
}
}
Complexity Analysis
- Time Complexity:
- Approach 1: O(N*N)
- Approach 2: O(N)
- Space Complexity:
- Approach 1: O(1)
- Approach 2: O(N)
A message containing letters from A-Z can be encoded into numbers using the following mapping:
...
To decode an encoded message, all the digits must be grouped then mapped back into letters using the reverse of the mapping above (there may be multiple ways). For example,
"11106" can be mapped into:
Note that the grouping (1 11 06) is invalid because "06" cannot be mapped into 'F' since "6" is different from "06".
Given a string s containing only digits, return the number of ways to decode it.
The test cases are generated so that the answer fits in a 32-bit integer.
Example 1:
Input: s = "12"
Output: 2
Explanation: "12" could be decoded as "AB" (1 2) or "L" (12).
Example 2:
Input: s = "226"
Output: 3
Explanation: "226" could be decoded as "BZ" (2 26), "VF" (22 6), or "BBF" (2 2 6).
Example 3:
Input: s = "06"
Output: 0
Explanation: "06" cannot be mapped to "F" because of the leading zero ("6" is different from "06").
Constraints:
Approach
- Approach
- take an dp array of size 1 greater than len(s)
- at the last index we'll keep 1
- for every char, if char not equal of 0
- dp[i] += dp[i+1]
- if s(i,i+2) is < 26
- dp[i] += dp[i+2]
- at last we'll have the ans at dp[0]
- Optimize
- pattern seems like fibonacci
- we can replace the array with three variables
- curr will have dp[i]
- prev will have dp[i+1]
- prev2 will have dp[i+2]
Solution
class Solution {
Complexity Analysis
- Time Complexity:
- Approach 1 & Approach 2: O(N)
- Space Complexity:
- Approach 1: O(N), dp array of n size
- Approach 2: O(1), 3 variables
You are given an integer array coins representing coins of different denominations and an integer amount representing a total amount of money.
Return the fewest number of coins that you need to make up that amount. If that amount of money cannot be made up by any combination of the coins, return -1.
You may assume that you have an infinite number of each kind of coin.
Example 1:
Input: coins = [1,2,5], amount = 11
Output: 3
Explanation: 11 = 5 + 5 + 1
Example 2:
Example 3:
Constraints:
Approach
- we'll have dp array of size amount+1
- we'll initiaze the array with large value
- dp[0] would be 0
- for in range(1, amount)
- for each coin
- dp[i] = min(dp[i], 1 + dp[i-coin])
- dp[amount] will either have the ans or else it'll have the default value
Solution
class Solution {
public int coinChange(int[] coins, int amount) {
int[] dp = new int[amount + 1];
Arrays.fill(dp, amount + 1);
dp[0] = 0;
for (int i = 1; i <= amount; i++) {
for (int j = 0; j < coins.length; j++) {
if (coins[j] <= i) {
dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1);
}
}
}
return dp[amount] > amount ? -1 : dp[amount];
}
}
Complexity Analysis
- Time Complex: O(N*K), N: amount+1, K = coins.length
- Space complexity: O(N), N: amount+1
Given an integer array nums, find a contiguous non-empty subarray within the array that has the largest product, and return the product.
The test cases are generated so that the answer will fit in a 32-bit integer.
Example 1:
Example 2:
Constraints:
Approach
- two variable to keep max & min at that index
- result, initially stores the max element present in the array
- if we encounter 0, min and max set to 1
- else
- min = min(min*arr[i],max*arr[i],arr[i])
- max = max(prevMin*arr[i], max*arr[i], arr[i])
- result = max(max, result)
Solution
class Solution {
public int maxProduct(int[] nums) {
int n = nums.length;
int min = nums[0], max = nums[0];
int result = nums[0];
return result;
}
}
Complexity Analysis
- Time Complexity: O(N)
- Space Complexity: O(1)
Given a string s and a dictionary of strings wordDict, return true if s can be segmented into a space-separated sequence of one or more dictionary words.
Note that the same word in the dictionary may be reused multiple times in the segmentation.
Example 1:
Example 2:
Example 3:
Constraints:
Approach
Decision tree of Backtracking
Cache
Bottom up
Solution
class Solution {
public boolean wordBreak(String s, List<String> wordDict) {
int n = s.length();
boolean dp[] = new boolean[n+1];
dp[n] = true;
if(dp[i])
break;
}
}
return dp[0];
}
}
Complexity Analysis
- Time Complexity: O(N*len(wordInDict))
- Space Complexity: O(N)
Given an integer array nums, return the length of the longest strictly increasing subsequence.
A subsequence is a sequence that can be derived from an array by deleting some or no elements without changing the order of the remaining elements. For example, [3,6,2,7] is a
subsequence of the array [0,3,1,6,2,2,7].
Example 1:
Example 2:
Example 3:
Constraints:
Approach
- Starting from 2nd last element, lis[] will store 1 for all the elements
- compare it with the next element, if the next element is less than current element
- add max of lis[curr], 1+lis[next]
Solution
class Solution {
public int lengthOfLIS(int[] nums) {
int n = nums.length;
int[] lis = new int[n];
Arrays.fill(lis, 1);
lis[n-1] = 1;
int res = 1;
for(int i = n-2; i >= 0; i--) {
for(int j = i+1; j < n; j++) {
if(nums[i] < nums[j])
lis[i] = Math.max(lis[i], 1+lis[j]);
}
res = Math.max(res, lis[i]);
}
return res;
}
}
Complexity Analysis
- Time Complexity: O(n^2)
- Space Complexity: O(n)
Given a non-empty array nums containing only positive integers, find if the array can be partitioned into two subsets such that the sum of elements in both subsets is equal.
Example 1:
Example 2:
Approach
- sum of all the elements, if it's odd return false
- otherwise, find whther there is a subset such that it's equal to sum/2
Solution
class Solution {
Boolean[][] dp;
public boolean canPartition(int[] nums) {
int sum = 0;
for(int num : nums) {
sum += num;
}
if(sum%2 != 0)
return false;
dp = new Boolean[nums.length][sum/2+1];
return subsetSum(nums, 0, sum/2);
}
// DP
private boolean subsetSum(int[] nums, int ind, int sum) {
if(ind >= nums.length || sum < 0)
return false;
if(sum == 0)
return true;
if(dp[ind][sum] != null)
return dp[ind][sum];
dp[ind][sum] = subsetSum(nums, ind+1, sum-nums[ind]) || subsetSum(nums, ind+1, sum);
return dp[ind][sum];
}
// Recursion
private boolean subsetSum2(int[] nums, int ind, int sum) {
if(ind >= nums.length)
return false;
if(sum == 0)
return true;
return subsetSum(nums, ind+1, sum-nums[ind]) || subsetSum(nums, ind+1, sum);
}
}
Complexity Analysis
- Time Complexity: O(N*Sum)
- Space Complexity: O(N*Sum)
Resources
62. Unique Paths
(https://leetcode.com/problems/unique-
paths/)
Medium
There is a robot on an m x n grid. The robot is initially located at the top-left corner (i.e., grid[0][0]). The robot tries to move to the bottom-right corner (i.e., grid[m - 1][n - 1]). The robot
can only move either down or right at any point in time.
Given the two integers m and n, return the number of possible unique paths that the robot can take to reach the bottom-right corner.
The test cases are generated so that the answer will be less than or equal to 2 * 109.
Example 1:
Input: m = 3, n = 7
Output: 28
Example 2:
Input: m = 3, n = 2
Output: 3
Explanation: From the top-left corner, there are a total of 3 ways to reach the bottom-right corner:
1. Right -> Down -> Down
2. Down -> Down -> Right
3. Down -> Right -> Down
Constraints:
Approach
- Last row and last column would have only one way
- others:
- dp[i][j] = dp[i+1][j]+dp[i][j+1];
- dp[0][0] would have the result
Solution
class Solution {
public int uniquePaths(int m, int n) {
int[][] dp = new int[m][n];
// last column
for(int i = 0; i < m; i++) {
dp[i][n-1] = 1;
}
// last row
for(int i = 0; i < n; i++) {
dp[m-1][i] = 1;
}
Complexity Analysis
- Time Complexity: O(m*n)
- Space Complexity: O(m*n)
Given two strings text1 and text2, return the length of their longest common subsequence. If there is no common subsequence, return 0.
A subsequence of a string is a new string generated from the original string with some characters (can be none) deleted without changing the relative order of the remaining
characters.
For example, "ace" is a subsequence of "abcde". A common subsequence of two strings is a subsequence that is common to both strings.
Example 1:
Example 2:
Example 3:
Constraints:
Approach
- Classic DP problem
- create a table, chars of one string as row and other as column
- fill out the value
- Formula that would appear
- if chars are equal: dp[i][j] = 1 + dp[i-1][j-1], (diagonally prev element)
- else: dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]), max(top element, left element)
Solution
class Solution {
public int longestCommonSubsequence(String text1, String text2) {
int n1 = text1.length(), n2 = text2.length();
int[][] dp = new int[n1+1][n2+1];
Complexity Analysis
- Time Compolexity: O(N*M), N : length of string 1, M : length of string 2
- Space Complexity: O(N*M)
You are given an array prices where prices[i] is the price of a given stock on the ith day.
Find the maximum profit you can achieve. You may complete as many transactions as you like (i.e., buy one and sell one share of the stock multiple times) with the following
restrictions:
After you sell your stock, you cannot buy stock on the next day (i.e., cooldown one day). Note: You may not engage in multiple transactions simultaneously (i.e., you must sell the
stock before you buy again).
Example 1:
Example 2:
Constraints:
Solution
class Solution {
public int maxProfit(int[] prices) {
boolean buy = false;
Map<String, Integer> mp = new HashMap<>();
return helper(prices, 0, mp, true);
}
private int helper(int[] prices, int index, Map<String, Integer> mp, boolean buying) {
if(index >= prices.length)
return 0;
if(mp.containsKey("("+index+","+buying+")"))
return mp.get("("+index+","+buying +")");
// in both the cases we have the cooldown
int cooldown = helper(prices, index+1, mp, buying);
if(buying) {
int buy = helper(prices, index+1, mp, !buying) - prices[index];
mp.put("("+index+","+buying +")", Math.max(cooldown, buy));
} else {
// we can't buy in next index so we pass the index+2
int sell = helper(prices, index+2, mp, !buying) + prices[index];
mp.put("("+index+","+buying +")", Math.max(cooldown, sell));
}
return mp.get("("+index+","+buying +")");
}
}
Complexity Analysis
- Time Complexity: O(N)
- Space Complexity: O(N)
You are given an integer array coins representing coins of different denominations and an integer amount representing a total amount of money.
Return the number of combinations that make up that amount. If that amount of money cannot be made up by any combination of the coins, return 0.
You may assume that you have an infinite number of each kind of coin.
Example 1:
Example 2:
Example 3:
Constraints:
Approach
- Make a table and go through a example
- generic recursive formula:
- dp[i][j] = dp[i-1][j] + dp[i][j-coin]
- take care of edge cases
Solution
class Solution {
public int change(int amount, int[] coins) {
int n = coins.length;
int dp[][] = new int[n][amount+1];
return dp[n-1][amount];
}
// Consise
public int change(int amount, int[] coins) {
int[][] dp = new int[coins.length+1][amount+1];
dp[0][0] = 1;
// Optimal
public int change(int amount, int[] coins) {
int[] dp = new int[amount + 1];
dp[0] = 1;
for (int coin : coins) {
for (int i = coin; i <= amount; i++) {
dp[i] += dp[i-coin];
}
}
return dp[amount];
}
}
Complexity Analysis
- Time Complexity: O(Amount*No. of coins)
- Space Complexity:
- 2D: O(Amount*No. of coins)
- Optimal: O(Amount+1)
329. Longest Increasing Path in a Matrix
(https://leetcode.com/problems/longest-
increasing-path-in-a-matrix/)
Hard
Given an m x n integers matrix, return the length of the longest increasing path in matrix.
From each cell, you can either move in four directions: left, right, up, or down. You may not move diagonally or move outside the boundary (i.e., wrap-around is not allowed).
Example 1:
Example 2:
Example 3:
Constraints:
m == matrix.length
n == matrix[i].length
1 <= m, n <= 200
0 <= matrix[i][j] <= 231 - 1
Approach
- DFS/backtracking with DP
- Start from each element in the matrix
- Find the longest increasing path we can make from that position
- by moving towards the 4 directions
- Store the result in a table
- Reuse the value
Solution
class Solution {
private int backtrack(int[][] matrix, int i, int j, int prev, int[][] cache) {
if(i < 0 || j < 0 || i >= matrix.length || j >= matrix[0].length || prev >= matrix[i][j])
return 0;
if(cache[i][j] != 0)
return cache[i][j];
int max = 1;
cache[i][j] = max;
return max;
}
}
Complexity Analysis
- Time Complexity: dfs: O(n*m), we'll go through each position, after that it'll return from any position in O(1)
- Space Complexity: O(n*m)
Share Given two strings word1 and word2, return the minimum number of operations required to convert word1 to word2.
Insert a character
Delete a character
Replace a character
Example 1:
Constraints:
Aproach
- make a table with one word as row and other as column,
- append same char at the start of the both words to represent that both are empty string then 0 operation rqd to convert from word
- generic recursive equation:
- dp[i][j] = dp[i-1][j-1], if char are same
- dp[i][j] = 1 + min(dp[i-1][j], dp[i-1][j-1], dp[i][j-1]), i.e. 1 + min(left, top, diagonally prev)
- take care of base cases
Solution
class Solution {
public int minDistance(String word1, String word2) {
int m = word1.length(), n = word2.length();
int dp[][] = new int[n+1][m+1];
for(int i = 1; i <= n; i++) {
dp[i][0] = i;
}
if(ch1 == ch2)
dp[i][j] = dp[i-1][j-1];
else
dp[i][j] = 1 + Math.min(dp[i-1][j], Math.min(dp[i-1][j-1], dp[i][j-1]));
}
}
return dp[n][m];
}
}
Complexity Analysis
- Time Complexity: O(len(word1)*len(word2))
- Space Complexity: O(len(word1)*len(word2))
Resources
53. Maximum Subarray
Easy
Given an integer array nums, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum.
Example 1:
Example 2:
Example 3:
Constraints:
Follow up: If you have figured out the O(n) solution, try coding another solution using the
divide and conquer approach, which is more subtle.
class Solution {
public int maxSubArray(int[] nums) {
int n = nums.length;
int total = 0;
int result = nums[0];
return result;
}
}
Return true if you can reach the last index, or false otherwise.
Example 1:
Example 2:
Constraints:
Aprroach
- one variable(for eg. ans) is keeping upto which index can we move from the current index
- if ans value is less than the current index, which means we can't move to the current index
- at every index we check if you can better the ans,
which means if we can move to a higher index than the current index stored in ans
- if ans is sotring the value more than equal to the length of the given array
Solution
class Solution {
public boolean canJump(int[] nums) {
int ans = 0, n = nums.length;
for(int i = 0; i < n-1; i++) {
if(ans < i)
return false;
if(ans < i+nums[i])
ans = i+nums[i];
if(ans >= n-1)
return true;
}
return ans >= n-1;
}
}
Complexity Analysis
- Time Complexity: O(N)
- Space Complexity: O(1)
Given an array of non-negative integers nums, you are initially positioned at the first index of the array.
Each element in the array represents your maximum jump length at that position.
Your goal is to reach the last index in the minimum number of jumps.
You can assume that you can always reach the last index.
Example 1:
Example 2:
Constraints:
Approach
- dp array initialized to large value, later on it will store the min jumps required to reach last index from each index
- we start from end, second last index, try to see if we can move to the last index
- for each index you look for the min step we need to reach last index
- Pattern:
- for each nums's index(i):
- for range(0,num) (j):
- dp[i] = min(dp[i], 1 + dp[i+j]
TODO : Optimization
Solution
class Solution {
public int jump(int[] nums) {
int n = nums.length;
int dp[] = new int[n];
Arrays.fill(dp, 10000);
dp[n - 1] = 0;
Complexity Analysis
- Time Complexity: O(k*N)
- Space Complexity: O(N)
There are n gas stations along a circular route, where the amount of gas at the ith station is gas[i].
You have a car with an unlimited gas tank and it costs cost[i] of gas to travel from the ith station to its next (i + 1)th station. You begin the journey with an empty tank at one of the gas
stations.
Given two integer arrays gas and cost, return the starting gas station's index if you can travel around the circuit once in the clockwise direction, otherwise return -1. If there exists a
solution, it is guaranteed to be unique
Example 1:
Example 2:
Constraints:
n == gas.length == cost.length
1 <= n <= 105
0 <= gas[i], cost[i] <= 104
Approach
- Trivial:
- we'll store the difference of gas[i]-cost[i]
- for all the +ve differences we do the process
TODO:Optimization
Solution
class Solution {
public int canCompleteCircuit(int[] gas, int[] cost) {
int ind = 0, sum = 0;
int[] diff = new int[gas.length];
PriorityQueue<Pair> pq = new PriorityQueue<>((a,b)->b.value-a.value);
for (int i = 0; i < gas.length; i++) {
diff[i] = gas[i] - cost[i];
sum += diff[i];
if(diff[i]>=0)
pq.offer(new Pair(diff[i], i));
}
if (sum < 0)
return -1;
while(!pq.isEmpty()) {
Pair p = pq.poll();
if (p.value >= 0) {
int pathSum = 0;
ind = p.index;
int j = p.index;
do {
pathSum += diff[j];
if (pathSum < 0)
break;
j = (j + 1) % gas.length;
} while(j != p.index);
if (pathSum >= 0)
break;
}
}
return ind;
}
}
class Pair {
int value;
int index;
Pair(int v, int i) {
value = v;
index = i;
}
}
Complexity Analysis
- Time Complexity: O(k*N), k is number of elements in diff array that are 0 or +ve
- Space Complexity: O(N)
Alice has some number of cards and she wants to rearrange the cards into groups so that each group is of size groupSize, and consists of groupSize consecutive cards.
Given an integer array hand where hand[i] is the value written on the ith card and an integer groupSize, return true if she can rearrange the cards, or false otherwise.
Example 1:
Example 2:
Constraints:
Approach
// TODO
Solution
class Solution {
public boolean isNStraightHand(int[] hand, int groupSize) {
if(hand.length % groupSize != 0)
return false;
while(!pq.isEmpty()) {
int min = pq.peek();
int sz = 0;
while(sz < groupSize) {
if(!mp.containsKey(min))
return false;
mp.put(min, mp.get(min)-1);
if(mp.get(min) == 0) {
mp.remove(min);
int val = pq.poll();
if(val != min)
return false;
}
min++;
sz++;
}
}
return true;
}
}
Complexity Analysis
- Time Complexity:
- Space Complexity:
Given a string s containing only three types of characters: '(', ')' and '*', return true if s is valid.
Any left parenthesis '(' must have a corresponding right parenthesis ')'. Any right parenthesis ')' must have a corresponding left parenthesis '('. Left parenthesis '(' must go before the
corresponding right parenthesis ')'. '*' could be treated as a single right parenthesis ')' or a single left parenthesis '(' or an empty string "".
Example 1:
Input: s = "()"
Output: true
Example 2:
Input: s = "(*)"
Output: true
Example 3:
Input: s = "(*))"
Output: true
Constraints:
Approach
Approach 1:
- backtrack
- count+1 if '('
- count-1 if ')'
- For '*':
- 3 calls: count+1, count-1, count+0
- dp (index, count) = true/false
Approach 2: greedy
Solution
class Solution {
Boolean[][] dp;
Complexity Analysis
- Time Complexity:
- Approach 1: O(n^3)
- Approach 2: O(n)
- Space Complexity:
- Approach 1: O(n)
- Approach 2: O(1)
Resources
57. Insert Interval
(https://leetcode.com/problems/insert-
interval/)
Medium
You are given an array of non-overlapping intervals intervals where intervals[i] = [starti, endi] represent the start and the end of the ith interval and intervals is sorted in ascending
order by starti. You are also given an interval newInterval = [start, end] that represents the start and end of another interval.
Insert newInterval into intervals such that intervals is still sorted in ascending order by starti and intervals still does not have any overlapping intervals (merge overlapping intervals if
necessary).
Example 1:
Constraints:
Approach
- Step 1: while interval's end is lesser than new interval's start, keep adding it to result
- After step 1, we'll be at the position where new interval will start(either overlap or as the initial interval or as the last inter
- Step 2: while intervals's start is <= new interval's end
- Keep taking the min start & max end and assign into the new interval(overlapping)
- After step 2, we'll have the merged new interval, add it to result
- Step 3: while intervals not finished processing
- keep adding them to the result
Solution
class Solution {
Complexity Analysis
- Time Complexity: O(n)
- Space Complexity: O(n)
Given an array of intervals where intervals[i] = [starti, endi], merge all overlapping intervals, and return an array of the non-overlapping intervals that cover all the intervals in the input.
Example 1:
Example 2:
Constraints:
Approach
- Sort the intervals by start time
- Use arr to store the merged list
- Start by inserting the first element
- looping through all the other intervals
- check if last interval inserted into arr overlapped with current interval
- if yes then create a new interval and push to arr
- else insert the current interval to arr
Solution
class Solution {
public int[][] merge(int[][] intervals) {
Arrays.sort(intervals, (a, b) -> a[0] - b[0]);
List<int[]> arr = new ArrayList<>();
arr.add(intervals[0]);
int start = intervals[0][0];
int end = intervals[0][1];
for (int i = 1; i < intervals.length; i++) {
int[] curr = intervals[i];
int[] prev = arr.get(arr.size() - 1);
if (curr[0] <= prev[1]) {
arr.remove(arr.size() - 1);
start = Math.min(curr[0], prev[0]);
end = Math.max(curr[1], prev[1]);
arr.add(new int[]{start, end});
} else {
arr.add(curr);
}
}
return arr.toArray(new int[arr.size()][]);
}
}
Complexity Analysis
- Time Complexity: O(nlogn)
- Space Complexity: O(n), for arr
Given an array of intervals intervals where intervals[i] = [starti, endi], return the minimum number of intervals you need to remove to make the rest of the intervals non-overlapping.
Example 1:
Example 2:
Example 3:
Constraints:
Approach
- Sort the intervals by end time
- store the first interval (we're storing it as prev)
- loop through the intervals starting the 2nd interval
- if current interval overlap with prev the increment the count
- else assign the current interval to the prev
Solution
class Solution {
public int eraseOverlapIntervals(int[][] intervals) {
if(intervals.length <= 1)
return 0;
Arrays.sort(intervals, (a,b)->a[1]-b[1]);
int count = 0;
int[] prev = intervals[0];
for(int i = 1; i < intervals.length; i++) {
int[] curr = intervals[i];
if(prev[1] > curr[0])
count++;
else
prev = intervals[i];
}
return count;
}
}
Complexity Analysis
- Time Complexity: O(nlogn)
- Space Complexity: O(1)
Description Given an array of meeting time intervals consisting of start and end times [[s1,e1],[s2,e2],...] (si < ei), determine if a person could attend all meetings.
Wechat reply the【Video】get the free video lessons , the latest frequent Interview questions , etc. (wechat id :jiuzhang15)
Example 1
Example 2
if(intervals.size() == 0 || intervals.size() == 1)
return true;
Collections.sort(intervals, (a,b)->a.end-b.end);
Interval next = intervals.get(intervals.size()-1);
for(int i = intervals.size()-2; i >= 0; i--) {
Interval current = intervals.get(i);
Given an array of meeting time intervals consisting of start and end times [[s1,e1],[s2,e2],...] (si < ei), find the minimum number of conference rooms required.)
Example 1
Example2
Approach
Approach 1:
- Create a array of size, largest element - smallest element + 1
- for each interval:
- increment all the index between [start, end)
- keep tracking the max element in that array, that's the answer
Approach 2(Better):
- Sort starting time and ending seperatedly
- Two pointers one from traversing through the start[] and the other through the end[]
- keep track of max count(it would have the answer)
- if pointer pointing at start < pointer pointing at end
- increment the count & move the start pointer forward
- else
- decrement the count & move the end pointer forward
Solution
/**
* Definition of Interval:
* public class Interval {
* int start, end;
* Interval(int start, int end) {
* this.start = start;
* this.end = end;
* }
* }
*/
return usedRooms;
}
}
Complexity Analysis
- Time Complexity:
- Better approach: O(nlogn)
- Space Complexity:
- Better approach: O(n)
Resources
48. Rotate Image
Medium
You are given an n x n 2D matrix representing an image, rotate the image by 90 degrees (clockwise).
You have to rotate the image in-place, which means you have to modify the input 2D matrix directly. DO NOT allocate another 2D matrix and do the rotation.
Example 1:
Example 2:
Constraints:
n == matrix.length == matrix[i].length
1 <= n <= 20
-1000 <= matrix[i][j] <= 1000
Approach
- Roatate = Transpose + Reverse
Solution
class Solution {
public void rotate(int[][] matrix) {
transpose(matrix);
for(int[] nums : matrix) {
reverse(nums);
}
}
Complexity Analysis
- Time Complexity: O(n), n : number of elements in the matrix
- Space Complexity: O(1)
54. Spiral Matrix
Medium
Example 1:
Example 2:
Constraints:
m == matrix.length
n == matrix[i].length
1 <= m, n <= 10
-100 <= matrix[i][j] <= 100
Approach
Solution
class Solution {
public List<Integer> spiralOrder(int[][] matrix) {
List<Integer> res = new ArrayList<>();
int m = matrix.length - 1;
int n = matrix[0].length - 1;
int sr = 0, sc = 0;
int i = sr, j = sc;
while (sc <= n || sr <= m) {
// 1st row
while (j <= n) {
res.add(matrix[i][j]);
j++;
}
sr++;
j = n;
i = sr;
// condition
if (i > m || j > n) {
break;
}
// last colunm
while (i <= m) {
res.add(matrix[i][j]);
i++;
}
n--;
i = m;
j = n;
if (i > m || j > n) {
break;
}
// last row
while (j >= sc) {
res.add(matrix[i][j]);
j--;
}
m--;
j = sc;
i = m;
if (i > m || j > n) {
break;
}
// 1st column
while (i >= sr) {
res.add(matrix[i][j]);
i--;
}
sc++;
i = sr;
j = sc;
if (i > m || j > n) {
break;
}
}
return res;
}
}
Complexity Analysis
- Time Complexity: O(n), n : number of elements in the matrix
- Space Complexity: O(1)
Given an m x n integer matrix matrix, if an element is 0, set its entire row and column to 0's.
Example 1:
Example 2:
Constraints:
m == matrix.length
n == matrix[0].length
1 <= m, n <= 200
-231 <= matrix[i][j] <= 231 - 1
Follow up:
Approach
- Use the first row and column to keep track of zeroes
- Use one variable for the 0th row or 0 column depending upon our choice
Solution
class Solution {
public void setZeroes(int[][] matrix) {
int col0 = 1;
int n = matrix.length, m = matrix[0].length;
// first column
for(int i = 0; i < n; i++) {
if(matrix[i][0] == 0)
col0 = 0;
}
// first row
for(int i = 0; i < m; i++) {
if(matrix[0][i] == 0)
matrix[0][0] = 0;
}
// starting from (1,1)
for(int i = 1; i < n; i++) {
for(int j = 1; j < m; j++) {
if(matrix[i][j] == 0) {
matrix[i][0] = 0;
matrix[0][j] = 0;
}
}
}
if(matrix[0][0] == 0) {
for(int i = 1; i < m; i++)
matrix[0][i] = 0;
}
if(col0 == 0) {
for(int i = 0; i < n; i++)
matrix[i][0] = 0;
}
}
}
Complexity Analysis
- Time Complexity: O(N), N : numbero of elements in the matrix
- Space Complexity: O(1)
Starting with any positive integer, replace the number by the sum of the squares of its digits.
Repeat the process until the number equals 1 (where it will stay), or it loops endlessly in a cycle which does not include 1.
Those numbers for which this process ends in 1 are happy.
Input: n = 19
Output: true
Explanation:
12 + 92 = 82
82 + 22 = 68
62 + 82 = 100
12 + 02 + 02 = 1
Example 2:
Input: n = 2
Output: false
Constraints:
class Solution {
public boolean isHappy(int n) {
int slow = n, fast = n;
do {
slow = sum(slow);
fast = sum(sum(fast));
} while(slow != fast);
return slow == 1;
You are given a large integer represented as an integer array digits, where each digits[i] is the ith digit of the integer. The digits are ordered from most significant to least significant in
left-to-right order. The large integer does not contain any leading 0's.
Increment the large integer by one and return the resulting array of digits.
Example 1:
Example 2:
Input: digits = [4,3,2,1]
Output: [4,3,2,2]
Explanation: The array represents the integer 4321.
Incrementing by one gives 4321 + 1 = 4322.
Thus, the result should be [4,3,2,2].
Example 3:
Constraints:
class Solution {
public int[] plusOne(int[] digits) {
int n = digits.length;
}
}
50. Pow(x, n)
(https://leetcode.com/problems/powx-n/)
Medium
Implement pow(x, n), which calculates x raised to the power n (i.e., xn).
Example 1:
Input: x = 2.00000, n = 10
Output: 1024.00000
Example 2:
Input: x = 2.10000, n = 3
Output: 9.26100
Example 3:
Input: x = 2.00000, n = -2
Output: 0.25000
Explanation: 2-2 = 1/22 = 1/4 = 0.25
Constraints:
Approach
- Recursiom:
- we can divide the power by 2 and same value can be reused
- For non-negative:
- for even: pow(x, n) = pow(x, n/2)*pow(x,n/2)
- for odd: - for even: pow(x, n) = x*pow(x, n/2)*pow(x,n/2)
- For negative:
- for even: pow(x, n) = pow(x, n/2)*pow(x,n/2)
- for odd: - for even: pow(x, n) = 1/x*pow(x, n/2)*pow(x,n/2)
Solution
class Solution {
public double myPow(double x, int n) {
if(n < 0)
return myPowNeg(x, n);
return myPowPos(x, n);
}
Complexity Analysis
- Time Complexity: O(logn)
- Space Complexity: O(logn)
Given two non-negative integers num1 and num2 represented as strings, return the product of num1 and num2, also represented as a string.
Note: You must not use any built-in BigInteger library or convert the inputs to integer directly.
Example 1:
Example 2:
Constraints:
Approach
- Reverse the number strings
- StringBuilder(mutable string) of 400 size, as num1 & num2 of 200 length at max
- calculate the multiplication and store overwrite it at the i+j position
- after each inner loop, we insert the carry at i+j position, j would be 1 position more the the original length of the second number
- reverse the string
- remove all the leading 0s
- return 0 if result string size is zero or else return thr result string
Solution
class Solution {
public String multiply(String num1, String num2) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 400; i++)
sb.append(0);
num1 = reverse(num1);
num2 = reverse(num2);
if(num1.length() > num2.length()) {
String tmp = num1;
num1 = num2;
num2 = tmp;
}
int carry = 0;
int i = 0, j = 0;
for (i = 0; i < num2.length(); i++) {
carry = 0;
for (j = 0; j < num1.length(); j++) {
int a = num2.charAt(i)-'0';
int b = num1.charAt(j)-'0';
int n = a * b + carry;
int prev = sb.charAt(i+j)-'0';
int sum = (prev + n) % 10;
carry = (n+prev) / 10;
sum +='0';
sb.setCharAt(i + j, (char) sum);
}
sb.setCharAt(i+j, (char) (carry+'0'));
}
Complexity Analysis
- Time Compexity: O(n*m)
- Space Complexity: O(400)
Resources
136. Single Number
Easy
Given a non-empty array of integers nums, every element appears twice except for one. Find that single one.
You must implement a solution with a linear runtime complexity and use only constant extra space.
Example 1:
Input: nums = [2,2,1]
Output: 1
Example 2:
Example 3:
Constraints:
class Solution {
public int singleNumber(int[] nums) {
int res = 0;
return res;
}
}
Write a function that takes an unsigned integer and returns the number of '1' bits it has (also known as the Hamming weight).
Note:
Note that in some languages, such as Java, there is no unsigned integer type. In this case, the input will be given as a signed integer type. It should not affect your implementation, as
the integer's internal binary representation is the same, whether it is signed or unsigned. In Java, the compiler represents the signed integers using 2's complement notation.
Therefore, in Example 3, the input represents the signed integer. -3.
Example 1:
Input: n = 00000000000000000000000000001011
Output: 3
Explanation: The input binary string 00000000000000000000000000001011 has a total of three '1' bits.
Example 2:
Input: n = 00000000000000000000000010000000
Output: 1
Explanation: The input binary string 00000000000000000000000010000000 has a total of one '1' bit.
Example 3:
Input: n = 11111111111111111111111111111101
Output: 31
Explanation: The input binary string 11111111111111111111111111111101 has a total of thirty one '1' bits.
Constraints:
The input must be a binary string of length 32.
Follow up: If this function is called many times, how would you optimize it?
while(n != 0) {
n = n & (n-1);
count++;
}
return count;
}
}
Given an integer n, return an array ans of length n + 1 such that for each i (0 <= i <= n), ans[i] is the number of 1's in the binary representation of i.
Example 1:
Input: n = 2
Output: [0,1,1]
Explanation:
0 --> 0
1 --> 1
2 --> 10
Example 2:
Input: n = 5
Output: [0,1,1,2,1,2]
Explanation:
0 --> 0
1 --> 1
2 --> 10
3 --> 11
4 --> 100
5 --> 101
Constraints:
Follow up:
It is very easy to come up with a solution with a runtime of O(n log n). Can you do it in linear time O(n) and possibly in a single pass?
Can you do it without using any built-in function (i.e., like __builtin_popcount in C++)?
class Solution {
public int[] countBits(int n) {
int[] dp = new int[n+1];
int offset = 1;
return dp;
}
}
class Solution {
public int[] countBits(int n) {
int[] dp = new int[n+1];
dp[i] = dp[i/2] + i % 2;
}
return dp;
}
}
Note:
Note that in some languages, such as Java, there is no unsigned integer type. In this case, both input and output will be given as a signed integer type. They should not affect
your implementation, as the integer's internal binary representation is the same, whether it is signed or unsigned. In Java, the compiler represents the signed integers using 2's
complement notation. Therefore, in Example 2 above, the input represents the signed integer -3 and the output represents the signed integer -1073741825.
Example 1:
Input: n = 00000010100101000001111010011100
Output: 964176192 (00111001011110000010100101000000)
Explanation: The input binary string 00000010100101000001111010011100 represents the unsigned integer 43261596, so return 964176192 w
Example 2:
Input: n = 11111111111111111111111111111101
Output: 3221225471 (10111111111111111111111111111111)
Explanation: The input binary string 11111111111111111111111111111101 represents the unsigned integer 4294967293, so return 322122547
Constraints:
Follow up: If this function is called many times, how would you optimize it?
public class Solution {
// you need treat n as an unsigned value
public int reverseBits(int n) {
int res = 0;
for(int i = 0; i < 32; i++) {
int bit = (n >> i) & 1; // check whether the bit is set or not [right shift each bit & 000..1] -> gives the value present
res = res | (bit << (31 - i)); // put the bit at 31 - i th position i.e, reverse
}
return res;
}
}
Given an array nums containing n distinct numbers in the range [0, n], return the only number in the range that is missing from the array.
Example 1:
Example 2:
Example 3:
Constraints:
n == nums.length
1 <= n <= 104
0 <= nums[i] <= n
All the numbers of nums are unique.
Follow up: Could you implement a solution using only O(1) extra space complexity and
O(n) runtime complexity?
class Solution {
public int missingNumber(int[] nums) {
int n = nums.length;
int sum = n * (n + 1) / 2;
Given two integers a and b, return the sum of the two integers without using the operators + and -.
Example 1:
Input: a = 1, b = 2
Output: 3
Example 2:
Input: a = 2, b = 3
Output: 5
Constraints:
Approach
Solution
Complexity Analysis
- Time Complexity:
- Space Complexity:
Resources
class UnionFind {
int[] root;
int[] rank;
UnionFind(int size) {
root = new int[size];
rank = new int[size];
if(rootX != rootY) {
if(rank[rootX] > rank[rootY])
root[rootY] = rootX;
else if(rank[rootX] < rank[rootY])
root[rootX] = rootY;
else {
root[rootY] = rootX;
rank[rootX]++;
}
}
}
You are given a 0-indexed 2D integer array grid of size m x n. Each cell has one of two values:
Return the minimum number of obstacles to remove so you can move from the upper left corner (0, 0) to the lower right corner (m - 1, n - 1).
Example 1:
Input: grid = [[0,1,1],[1,1,0],[1,1,0]]
Output: 2
Explanation: We can remove the obstacles at (0, 1) and (0, 2) to create a path from (0, 0) to (2, 2).
It can be shown that we need to remove at least 2 obstacles, so we return 2.
Note that there may be other ways to remove 2 obstacles to create a path.
Example 2:
Constraints:
m == grid.length
n == grid[i].length
1 <= m, n <= 105
2 <= m * n <= 105
grid[i][j] is either 0 or 1.
grid[0][0] == grid[m - 1][n - 1] == 0
Approach
- Node class to store distance, row number, column number, done processing
- Map to store the key and the node for that key
- priority queue based on distance
- add the source to pq, with distance 0
- while pq not empty, poll a node
- if node is not done
- mark it done
- check all it's neighbour's distance with the node.dsitance+grid[neighbour's row][neighbour's col]
- update the distance of neighbour if it's greater than above calculated distance
- and add the neighbour into the pq
Solution
class Solution {
class Node {
int dist;
int i;
int j;
boolean done;
Node(int d, int ii, int jj, boolean done) {
dist = d;
i = ii;
j = jj;
done = done;
}
}
pq.offer(mp.get("0,0"));
while(!pq.isEmpty()) {
Node node = pq.poll();
if(node.done == false) {
node.done = true;
int i = node.i;
int j = node.j;
for(int[] dir:dirs) {
int new_i = i+dir[0];
int new_j = j+dir[1];
if(new_i >= 0 && new_i < n && new_j >= 0 && new_j < m) {
String neiK = ""+new_i+","+new_j;
Node nei = mp.get(neiK);
int cost = node.dist+grid[new_i][new_j];
if(cost < nei.dist) {
nei.dist = cost;
pq.offer(mp.get(neiK));
}
}
}
}
}
return mp.get(""+(n-1)+","+(m-1)).dist;
}
}
Complexity Analysis
- Time Complexity: O(n*m log (n*m))
- Space Complexity: O(n*m)
BFS on Graph
• Undiscovered – the vertex is in its initial, virgin state.
• Discovered – the vertex has been found, but we have not yet checked out all its incident edges.
• Processed – the vertex after we have visited all of its incident edges
public Graph(int v) {
degree = new int[v];
nvertices = v;
nedges = 0;
adjList = new HashMap<>();
for(int i = 0; i < v; i++) {
adjList.put(i, new ArrayList<>());
}
}
Graph g;
public BfsGraph(Graph g) {
this.g = g;
processed = new boolean[g.nvertices];
discovered = new boolean[g.nvertices];
parent = new int[g.nvertices];
for(int i = 0; i < g.nvertices; i++)
parent[i] = -1;
}
q.offer(start);
discovered[start] = true;
while (!q.isEmpty()) {
v = q.poll();
// process vertex early - v
System.out.println(v);
processed[v] = true;
List<int[]> neighbors = g.adjList.get(v);
for(int[] neighbor : neighbors) {
y = neighbor[0];
if(!processed[y] || g.directed) {
// process edge(v, y)
System.out.println(v+"-"+y);
}
if(!discovered[y]) {
q.offer(y);
discovered[y] = true;
parent[y] = v;
}
}
// process vertex late - v
}
}
However, Dijkstra’s algorithm can fail when the graph has negative edge weights. This is when BF becomes really handy because it can be used to detect negative cycles and
determine where they occur.Finding negative cycles can be useful in many types of applications. One particularly neat application arises in finance when performing an
arbitragebetween two or more markets.
Approach
public class BellmanFordEdgeList {
// A directed edge
public static class Edge {
double cost;
int from, to;
/**
* An implementation of the Bellman-Ford algorithm. The algorithm finds the shortest path between
* a starting node and all other nodes in the graph. The algorithm also detects negative cycles.
* If a node is part of a negative cycle then the minimum cost for that node is set to
* Double.NEGATIVE_INFINITY.
*
* @param edges - An edge list containing directed edges forming the graph
* @param V - The number of vertices in the graph.
* @param start - The id of the starting node
*/
public static double[] bellmanFord(Edge[] edges, int V, int start) {
// Only in the worst case does it take V-1 iterations for the Bellman-Ford
// algorithm to complete. Another stopping condition is when we're unable to
// relax an edge, this means we have reached the optimal solution early.
boolean relaxedAnEdge = true;
Implement strStr().
Given two strings needle and haystack, return the index of the first occurrence of needle in haystack, or -1 if needle is not part of haystack.
Clarification:
What should we return when needle is an empty string? This is a great question to ask during an interview.
For the purpose of this problem, we will return 0 when needle is an empty string. This is consistent to C's strstr() and Java's indexOf().
Example 1:
Constraints:
Approach
- build pattern:
- we build the pattern for the substring
- it would be use in matching the pattern
- how:
- initialize two pointers, starting from 0(j) and 1(i)
- while i < len(substring)
- if s[i] == s[j] then set pattern[i] = j and increment both pointers, (which means we found a suffix that matches a prefix)
- else if j > 0 then set j to pattern[j-1]+1, (j-1 holds the last index where it had a successful match)
- else increment i
- matching pattern
- similar to build pattern
- how:
- initialize two pointers, starting from 0(j) points to sunstring and 0(i) points to string
- while i + len(substring) - j <= len(string)
- if s[i] == s[j]
- if j = len(substring)-1
- we found the match
- increment both pointers,
- else if j > 0 then set j to pattern[j-1]+1, (j-1 holds the last index where it had a successful match)
- else increment i
Solution
class Solution {
public int strStr(String haystack, String needle) {
int[] pattern = new int[needle.length()];
Arrays.fill(pattern, -1);
buildPattern(needle, pattern);
return matchIndex(haystack, needle, pattern);
}
Complexity Analysis
- Time Complexity: O(n+m), n - length of string, m - length of substring
- Space Complexity: O(m), to build the pattern array
Segment Tree
Introduction
Approach
Implementation
class SegmentTree { // the segment tree is stored like a heap array
private int[] st, A;
private int n;
private int left(int p) {
return p << 1;
} // same as binary heap operations
private int right(int p) {
return (p << 1) + 1;
}
// compute the min position in the left and right part of the interval
int p1 = rmq(left(p), L, (L + R) / 2, i, j);
int p2 = rmq(right(p), (L + R) / 2 + 1, R, i, j);
Complexity Analysis
- Time Complexity:
- Space Complexity:
Fenwick Tree
Introduction
Approach
Implementation
class FenwickTree {
int[] ft, nums;
Complexity Analysis
- Time Complexity:
- Space Complexity:
Fenwick Tree
Introduction
Approach
Implementation
public class FenwickTree2D {
int[][] ft;
public int rangeSum(int x1, int y1, int x2, int y2) {
// Inclusion & Exclusion principle
return querySum(x2, y2) - querySum(x1 - 1, y2) - querySum(x2, y1 - 1) + querySum(x1 - 1, y1 - 1);
}
}
Complexity Analysis
- Time Complexity:
- Space Complexity:
NeetCode-150
1. Arrays & Hashing Resources
(https://github.com/dipjul/NeetCode-
150/blob/main/01.%20Arrays%20&%20Hashing/)
1. Contains Duplicate Solution (https://github.com/dipjul/NeetCode-150/blob/main/01.%20Arrays%20&%20Hashing/01.%20ContainsDuplicate.md)
2. Valid Anagram Solution (https://github.com/dipjul/NeetCode-150/blob/main/01.%20Arrays%20&%20Hashing/02.ValidAnagram.md)
3. Two Sum Solution (https://github.com/dipjul/NeetCode-150/blob/main/01.%20Arrays%20&%20Hashing/03.TwoSum.md)
4. Group Anagrams Solution (https://github.com/dipjul/NeetCode-150/blob/main/01.%20Arrays%20&%20Hashing/04.GroupAnagrams.md)
5. Top K Frequent Elements Solution (https://github.com/dipjul/NeetCode-150/blob/main/01.%20Arrays%20&%20Hashing/05.TopKElements.md)
6. Product of Array Except Self Solution (https://github.com/dipjul/NeetCode-150/blob/main/01.%20Arrays%20&%20Hashing/06.ProductOfArrayExceptSelf.md)
7. Valid Sudoku Solution (https://github.com/dipjul/NeetCode-150/blob/main/01.%20Arrays%20&%20Hashing/07.ValidSodoku.md)
8. Encode And Decode Strings Solution (https://github.com/dipjul/NeetCode-150/blob/main/01.%20Arrays%20&%20Hashing/08.EncodeAndDecodeStrings.md)
9. Longest Consecutive Sequence Solution (https://github.com/dipjul/NeetCode-150/blob/main/01.%20Arrays%20&%20Hashing/09.LongestConsecutiveSequence.md)
Given an integer array nums, return true if any value appears at least twice in the array, and return false if every element is distinct.
Example 1:
Example 2:
Example 3:
Input: nums = [1,1,1,3,3,4,3,2,4,2]
Output: true
Constraints:
class Solution {
public boolean containsDuplicate(int[] nums) {
Set<Integer> set = new HashSet<>();
for(int num : nums) {
if(!set.add(num))
return true;
}
return false;
}
}
Given two strings s and t, return true if t is an anagram of s, and false otherwise.
An Anagram is a word or phrase formed by rearranging the letters of a different word or phrase, typically using all the original letters exactly once.
Example 1:
Example 2:
Constraints:
class Solution {
public boolean isAnagram(String s, String t) {
if(s.length() != t.length())
return false;
for(int n : chars) {
if(n != 0)
return false;
}
return true;
}
}
Follow up: What if the inputs contain Unicode characters? How would you adapt your
solution to such a case?
We can be used a map, or a array of size equal to the characterset size of unicode.
1. Two Sum
Easy
Given an array of integers nums and an integer target, return indices of the two numbers such that they add up to target.
You may assume that each input would have exactly one solution, and you may not use the same element twice.
Example 1:
Example 2:
Example 3:
Constraints:
Follow-up: Can you come up with an algorithm that is less than O(n2) time complexity?
class Solution {
public int[] twoSum(int[] nums, int target) {
int n = nums.length;
Map<Integer, Integer> map = new HashMap<>();
Given an array of strings strs, group the anagrams together. You can return the answer in any order.
An Anagram is a word or phrase formed by rearranging the letters of a different word or phrase, typically using all the original letters exactly once.
Example 1:
Example 2:
Example 3:
Constraints:
class Solution {
// 1
public List<List<String>> groupAnagrams(String[] strs) {
List<List<String>> res = new ArrayList<>();
Map<String, List<String>> mp = new HashMap<>();
for (String str : strs) {
char[] c = str.toCharArray();
Arrays.sort(c);
String r = new String(c);
if (!mp.containsKey(r))
mp.put(r, new ArrayList<String>());
mp.get(r).add(str);
}
for (String key : mp.keySet()) {
res.add(mp.get(key));
}
return res;
}
// 2
public List<List<String>> groupAnagrams(String[] strs) {
List<List<String>> res = new ArrayList<>();
Map<String, List<String>> mp = new HashMap<>();
for (String str : strs) {
char[] hash = new char[26];
for(char ch : str.toCharArray())
hash[ch-'a']++;
String r = new String(hash);
if (!mp.containsKey(r))
mp.put(r, new ArrayList<String>());
mp.get(r).add(str);
}
for (String key : mp.keySet()) {
res.add(mp.get(key));
}
return res;
}
}
347. Top K Frequent Elements
Medium
Given an integer array nums and an integer k, return the k most frequent elements. You may return the answer in any order.
Example 1:
Example 2:
Constraints:
Follow up: Your algorithm's time complexity must be better than O(n log n), where n is the
array's size.
class Solution {
public int[] topKFrequent(int[] nums, int k) {
Map<Integer, Integer> mp = new HashMap<>();
int[] res = new int[k];
for(int num : nums) {
mp.put(num, mp.getOrDefault(num,0)+1);
}
PriorityQueue<Pair> pq = new PriorityQueue<>((a,b)->b.val-a.val);
for(int key : mp.keySet())
pq.offer(new Pair(key, mp.get(key)));
for(int i = 0; i < k; i++)
res[i] = pq.poll().key;
return res;
}
}
class Pair {
int key;
int val;
Pair(int k, int v) {
key = k;
val = v;
}
}
Given an integer array nums, return an array answer such that answer[i] is equal to the product of all the elements of nums except nums[i].
The product of any prefix or suffix of nums is guaranteed to fit in a 32-bit integer.
You must write an algorithm that runs in O(n) time and without using the division operation.
Example 1:
Example 2:
Constraints:
Follow up: Can you solve the problem in O(1) extra space complexity? (The output array
does not count as extra space for space complexity analysis.)
class Solution {
public int[] productExceptSelf(int[] nums) {
int n = nums.length;
int[] res = new int[n];
int pre = 1;
res[0] = 1;
for(int i = 0; i < n-1; i++) {
pre *= nums[i];
res[i+1] = pre;
}
int post = 1;
for(int i = n-1; i > 0; i--) {
post *= nums[i];
res[i-1] *= post;
}
return res;
}
}
Determine if a 9 x 9 Sudoku board is valid. Only the filled cells need to be validated according to the following rules:
Note:
A Sudoku board (partially filled) could be valid but is not necessarily solvable.
Only the filled cells need to be validated according to the mentioned rules.
Example 1:
Input: board =
[["5","3",".",".","7",".",".",".","."]
,["6",".",".","1","9","5",".",".","."]
,[".","9","8",".",".",".",".","6","."]
,["8",".",".",".","6",".",".",".","3"]
,["4",".",".","8",".","3",".",".","1"]
,["7",".",".",".","2",".",".",".","6"]
,[".","6",".",".",".",".","2","8","."]
,[".",".",".","4","1","9",".",".","5"]
,[".",".",".",".","8",".",".","7","9"]]
Output: true
Example 2:
Input: board =
[["8","3",".",".","7",".",".",".","."]
,["6",".",".","1","9","5",".",".","."]
,[".","9","8",".",".",".",".","6","."]
,["8",".",".",".","6",".",".",".","3"]
,["4",".",".","8",".","3",".",".","1"]
,["7",".",".",".","2",".",".",".","6"]
,[".","6",".",".",".",".","2","8","."]
,[".",".",".","4","1","9",".",".","5"]
,[".",".",".",".","8",".",".","7","9"]]
Output: false
Explanation: Same as Example 1, except with the 5 in the top left corner being modified to 8. Since there are two 8's in the top left 3x3 sub-box, it is invalid.
Constraints:
board.length == 9
board[i].length == 9
board[i][j] is a digit 1-9 or '.'.
// My Solution
class Solution {
public boolean isValidSudoku(char[][] board) {
return true;
}
Example1
Input: ["lint","code","love","you"]
Output: ["lint","code","love","you"]
Explanation:
One possible encode method is: "lint:;code:;love:;you"
Example2
/*
* @param str: A string
* @return: dcodes a single string to a list of strings
*/
public List<String> decode(String str) {
Given an unsorted array of integers nums, return the length of the longest consecutive elements sequence.
Example 1:
Example 2:
Constraints:
Resources
Youtube (https://youtu.be/shs0KM3wKv8)
Leetcode Discussion (https://leetcode.com/discuss/general-discussion/1068545/HASH-TABLE-and-MAP-POWERFUL-GUIDE-!!!)
A phrase is a palindrome if, after converting all uppercase letters into lowercase letters and removing all non-alphanumeric characters, it reads the same forward and backward.
Alphanumeric characters include letters and numbers.
Example 1:
Example 2:
Example 3:
Constraints:
return true;
}
}
Given a 1-indexed array of integers numbers that is already sorted in non-decreasing order, find two numbers such that they add up to a specific target number. Let these two
numbers be numbers[index1] and numbers[index2] where 1 <= index1 < index2 <= numbers.length.
Return the indices of the two numbers, index1 and index2, added by one as an integer array [index1, index2] of length 2.
The tests are generated such that there is exactly one solution. You may not use the same element twice.
Example 1:
Example 2:
Example 3:
Constraints:
15. 3Sum
Medium
Given an integer array nums, return all the triplets [nums[i], nums[j], nums[k]] such that i != j, i != k, and j != k, and nums[i] + nums[j] + nums[k] == 0.
Notice that the solution set must not contain duplicate triplets.
Example 1:
Example 2:
Input: nums = []
Output: []
Example 3:
Constraints:
You are given an integer array height of length n. There are n vertical lines drawn such that the two endpoints of the ith line are (i, 0) and (i, height[i]).
Find two lines that together with the x-axis form a container, such that the container contains the most water.
Example 1:
Example 2:
Constraints:
n == height.length
2 <= n <= 105
0 <= height[i] <= 104
class Solution {
public int maxArea(int[] height) {
int area = 0, maxArea = 0;
int left = 0, right = height.length-1;
return maxArea;
}
}
Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it can trap after raining.
Example 1:
Example 2:
Constraints:
n == height.length
1 <= n <= 2 * 104
0 <= height[i] <= 105
Approach
First Approach:
- leftMax array to keep the max element on the left of the index
- rightMax array to keep the max element on the right of the index
- at each index take the min(leftMax, rightMax) - heigh[index], if it's greater than 0 add it to ans
- Time : O(N)
- Space: O(N)
Second Approach:
- instead of keep arrays to store the leftmax & rightMax, we can use two variables
- if leftMax <= rightMax
- try to update leftMax
- if min(leftMax, rightMax) - heigh[index] > 0, add it to ans
- move the left pointer ahead
- else
- same as above just replacing the left's by right
- decrement the right pointer
Solution
class Solution {
public int trap(int[] height) {
int left = 0, right = height.length-1;
int lMax = height[0], rMax = height[right];
int ans = 0;
while(left <= right) {
if(lMax <= rMax) {
lMax = Math.max(lMax, height[left]);
int val = Math.min(lMax, rMax)-height[left];
ans += val < 0 ? 0 : val;
left++;
} else {
rMax = Math.max(rMax, height[right]);
int val = Math.min(lMax, rMax)-height[right];
ans += val < 0 ? 0 : val;
right--;
}
}
return ans;
}
}
Complexity Analysis
- Time Complexity: O(N) -> go through each elements of the height array
- Space Complexity: O(1)
Resources
Youtube (https://youtu.be/-gjxg6Pln50)
Leetcode Discussion (https://leetcode.com/discuss/study-guide/1688903/Solved-all-two-pointers-problems-in-100-days.)
You are given an array prices where prices[i] is the price of a given stock on the ith day.
You want to maximize your profit by choosing a single day to buy one stock and choosing a different day in the future to sell that stock.
Return the maximum profit you can achieve from this transaction. If you cannot achieve any profit, return 0.
Example 1:
Input: prices = [7,1,5,3,6,4]
Output: 5
Explanation: Buy on day 2 (price = 1) and sell on day 5 (price = 6), profit = 6-1 = 5.
Note that buying on day 2 and selling on day 1 is not allowed because you must buy before you sell.
Example 2:
Constraints:
class Solution {
public int maxProfit(int[] prices) {
int n = prices.length;
if(n == 1) return 0;
int maxP = 0;
int l = 0, r = 1;
while(r < n) {
if(prices[l] < prices[r]) {
int profit = prices[r] - prices[l];
maxP = Math.max(maxP, profit);
} else
l = r;
r++;
}
return maxP;
}
}
Given a string s, find the length of the longest substring without repeating characters.
Example 1:
Input: s = "abcabcbb"
Output: 3
Explanation: The answer is "abc", with the length of 3.
Example 2:
Input: s = "bbbbb"
Output: 1
Explanation: The answer is "b", with the length of 1.
Example 3:
Input: s = "pwwkew"
Output: 3
Explanation: The answer is "wke", with the length of 3.
Notice that the answer must be a substring, "pwke" is a subsequence and not a substring.
Constraints:
class Solution {
public int lengthOfLongestSubstring(String s) {
Map<Character, Integer> mp = new HashMap<>();
int maxLen = 0, winStart = 0;
You are given a string s and an integer k. You can choose any character of the string and change it to any other uppercase English character. You can perform this operation at most
k times.
Return the length of the longest substring containing the same letter you can get after performing the above operations.
Example 1:
Input: s = "ABAB", k = 2
Output: 4
Explanation: Replace the two 'A's with two 'B's or vice versa.
Example 2:
Input: s = "AABABBA", k = 1
Output: 4
Explanation: Replace the one 'A' in the middle with 'B' and form "AABBBBA".
The substring "BBBB" has the longest repeating letters, which is 4.
Constraints:
Notes
- use a map to store the frequency
- maxRepeatingCharCount = max(maxRepeatingCharCount, mp.get(char))
- slide the left pointer until the equation satifies: windowEnd - windowStart + 1 - maxRepeatingCharCount > k
- maxLen = max(maxLen, windowEnd - windowStart + 1)
Solution:
class Solution {
public int characterReplacement(String s, int k) {
int windowStart = 0, maxLength = 0, mostRepeatingCharCount = 0;
return maxLength;
}
}
Given two strings s1 and s2, return true if s2 contains a permutation of s1, or false otherwise.
In other words, return true if one of s1's permutations is the substring of s2.
Example 1:
Example 2:
Constraints:
Approach
- 2 array of size 26 to keep count of chars present in both the strings[s1 and substring of s2]
- match keeps the number of characters matches in both s1 and substring of s2
- if matches = 26, we have a permutation in that window
- on each window, we check for conditions [ for both the chars(at left and at right) ]:
- increment s2Map[rightCharInd]++ and decrement s2Map[leftCharInd]--
- if the char's count are same increment the matches
- if the char's count differ by 1
- right: s1Map[rightCharInd] + 1 == s2Map[rightCharInd],
- left: s1Map[leftCharInd] - 1 == s2Map[leftCharInd] decrement the matches
Solution
class Solution {
public boolean checkInclusion(String s1, String s2) {
if(s1.length() > s2.length())
return false;
char[] s1Map = new char[26];
char[] s2Map = new char[26];
int matches = 0;
for(int i = 0; i < 26; i++) {
if(s1Map[i] == s2Map[i])
matches++;
}
int windowStart = 0;
for(int windowEnd = s1.length(); windowEnd < s2.length(); windowEnd++) {
if(matches == 26) return true;
int rightCharInd = s2.charAt(windowEnd)-'a';
s2Map[rightCharInd]++;
if(s1Map[rightCharInd] == s2Map[rightCharInd])
matches++;
else if(s1Map[rightCharInd] + 1 == s2Map[rightCharInd])
matches--;
windowStart++;
}
Complexity Analysis:
Time Complexity: O(s2.length())
Space Complexity: O(26) ~ O(1)
Given two strings s and t of lengths m and n respectively, return the minimum window substring of s such that every character in t (including duplicates) is included in the window. If
there is no such substring, return the empty string "".
The testcases will be generated such that the answer is unique.
Example 1:
Example 2:
Example 3:
Constraints:
m == s.length
n == t.length
1 <= m, n <= 105
s and t consist of uppercase and lowercase English letters.
Approach
- Try to increase the window untill we have all the characters of the pattern
- Once we get the pattern, we update the result if length is less than earlier
- Shrink the window while the window have all the required characters & update the result
Solution
Approach 1
class Solution {
public String minWindow(String s, String t) {
int winS = 0, winE = 0;
String ans = "";
Map<Character, Integer> tMp = new HashMap<>();
Map<Character, Integer> wMp = new HashMap<>();
for(char c : t.toCharArray()) {
tMp.put(c, tMp.getOrDefault(c, 0)+1);
}
while(winS < s.length() && winE < s.length()) {
char c = s.charAt(winE);
wMp.put(c, wMp.getOrDefault(c, 0)+1);
while(winS <= winE && satisfy(wMp, tMp)) {
if(ans == "")
ans = s.substring(winS, winE+1);
ans = (winE-winS+1) < ans.length()?s.substring(winS, winE+1):ans;
wMp.put(s.charAt(winS), wMp.get(s.charAt(winS))-1);
if(wMp.get(s.charAt(winS)) == 0)
wMp.remove(s.charAt(winS));
winS++;
}
winE++;
}
return ans;
}
Approach 2 (Optimized)
class Solution {
public String minWindow(String str, String pattern) {
int windowStart = 0, minLen = Integer.MAX_VALUE, matched = 0;
Map<Character, Integer> charFreqMap = new HashMap<>();
String res = "";
for (char ch : pattern.toCharArray())
charFreqMap.put(ch, charFreqMap.getOrDefault(ch, 0) + 1);
if (charFreqMap.containsKey(right)) {
charFreqMap.put(right, charFreqMap.get(right) - 1);
if (charFreqMap.get(right) == 0)
matched++;
}
Complexity Analysis
Approach 1:
- Time Complexity: O(N*K), N: length of str, K: length of pattern
- Space Complexity: O(K), K: length of pattern
Approach 2:
- Time Complexity: O(N), N: length of str
- Space Complexity: O(K), K: length of pattern
You are given an array of integers nums, there is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the
window. Each time the sliding window moves right by one position.
Example 1:
Input: nums = [1,3,-1,-3,5,3,6,7], k = 3
Output: [3,3,5,5,6,7]
Explanation:
Window position Max
--------------- -----
[1 3 -1] -3 5 3 6 7 3
1 [3 -1 -3] 5 3 6 7 3
1 3 [-1 -3 5] 3 6 7 5
1 3 -1 [-3 5 3] 6 7 5
1 3 -1 -3 [5 3 6] 7 6
1 3 -1 -3 5 [3 6 7] 7
Example 2:
Constraints:
Approach
- Use Deque, to keep the elements
- we'll keep the elemenet in decreasing order
- while the element at the first of the queue, i.e the index of the nums,
if it's out of the window, keep removing the element
- while the element at the last of the queue, i.e the index,
if it's less than equal to new element of the nums, keep removing the element
- insert the index of new element of nums
- if wE greater than k-1, then add the first element (index of the element in nums)
of the queue to res
Solution
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
int[] res = new int[nums.length - k + 1];
int wS = 0, s = 0;
ArrayDeque<Integer> q = new ArrayDeque<>();
// while the element at the last of the queue, i.e the index,
// if it's less than equal to new element of the nums,
// keep removing the element
while(!q.isEmpty() && nums[q.peekLast()] <= nums[wE])
q.pollLast();
Complexity Analysis
- Time Complexity: O(n)
- Space Complexity: O(k), where k < n
Resources
Leetcode - template (https://leetcode.com/problems/minimum-window-substring/discuss/26808/Here-is-a-10-line-template-that-can-solve-most-%27substring%27-problems)
Leetcode - Overview & Question bank (https://leetcode.com/discuss/study-guide/1773891/Sliding-Window-Technique-and-Question-Bank)
Youtube Playlist - Hindi (https://youtube.com/playlist?list=PL_z_8CaSLPWeM8BDJmIYDaoQ5zuwyxnfj)
Youtube Playlist - Neetcode (https://youtube.com/playlist?list=PLot-Xpze53leOBgcVsJBEGrHPd_7x_koV)
Given a string s containing just the characters '(', ')', '{', '}', '[' and ']', determine if the input string is valid.
Example 1:
Input: s = "()"
Output: true
Example 2:
Input: s = "()[]{}"
Output: true
Example 3:
Input: s = "(]"
Output: false
Constraints:
class Solution {
public boolean isValid(String s) {
Stack<Character> st = new Stack<>();
return st.empty();
}
}
Design a stack that supports push, pop, top, and retrieving the minimum element in constant time.
Example 1:
Input
["MinStack","push","push","push","getMin","pop","top","getMin"]
[[],[-2],[0],[-3],[],[],[],[]]
Output
[null,null,null,null,-3,null,0,-2]
Explanation
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin(); // return -3
minStack.pop();
minStack.top(); // return 0
minStack.getMin(); // return -2
Constraints:
Pair(int v, int m) {
val = v;
min = m;
}
void setVal(int v) {
val = v;
}
void setMin(int m) {
min = m;
}
}
class MinStack {
Stack<Pair> st;
public MinStack() {
st = new Stack<>();
}
/**
* Your MinStack object will be instantiated and called as such:
* MinStack obj = new MinStack();
* obj.push(val);
* obj.pop();
* int param_3 = obj.top();
* int param_4 = obj.getMin();
*/
Valid operators are +, -, *, and /. Each operand may be an integer or another expression.
Note that division between two integers should truncate toward zero.
It is guaranteed that the given RPN expression is always valid. That means the expression would always evaluate to a result, and there will not be any division by zero operation.
Example 1:
Example 2:
Example 3:
Constraints:
Solution
class Solution {
public int evalRPN(String[] tokens) {
Stack<Integer> st = new Stack<>();
for(String s : tokens) {
if(s.equals("+")) {
st.push(st.pop()+st.pop());
} else if(s.equals("-")) {
int n2 = st.pop();
int n1 = st.pop();
st.push(n1-n2);
} else if(s.equals("*")) {
st.push(st.pop()*st.pop());
} else if(s.equals("/")) {
int n2 = st.pop();
int n1 = st.pop();
st.push(n1/n2);
} else {
st.push(Integer.parseInt(s));
}
}
return st.peek();
}
}
Comlexity Analysis
Time Complexity: O(N) -> traversing through all the tokens
Space Complexity: O(N) -> for the stack
22. Generate Parentheses
Medium
Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses.
Example 1:
Input: n = 3
Output: ["((()))","(()())","(())()","()(())","()()()"]
Example 2:
Input: n = 1
Output: ["()"]
Constraints:
1 <= n <= 8
Approach
- Backtracking
- add '(' always and add ')' only if count('(') > count(')')
- add the string into the result when count('(') > count(')') && count('(') == n
- base case: count('(') > n || count(')') > n
Solution
class Solution {
public List<String> generateParenthesis(int n) {
List<String> ans = new ArrayList<>();
generate(0, n, 0, 0, ans, "");
return ans;
}
private void generate(int index, int n, int lCount, int rCount, List<String> ans, String op) {
if(lCount > n || rCount > n)
return;
if(lCount == rCount && lCount == n) {
ans.add(op);
}
if(lCount > rCount) {
String op1 = op + ")";
generate(index+1, n, lCount, rCount+1, ans, op1);
}
String op2 = op + "(";
generate(index+1, n, lCount+1, rCount, ans, op2);
}
}
Example 1:
Example 2:
Example 3:
Constraints:
Approach
- Use a stack to keep temperatures and indices
- We'll check while peek element is less the current temperature
- We'll pop and res[popped Index] = i-popped Index;
- push each element and index to the stack
return res;
}
}
Complexity Analysis
- Time Complexity: O(N)
At first glance, it may look like the time complexity of this algorithm should be O(N^2),
because there is a nested while loop inside the for loop. However, each element can only be added to the stack once,
which means the stack is limited to N pops. Every iteration of the while loop uses 1 pop,
which means the while loop will not iterate more than N times in total, across all iterations of the for loop.
An easier way to think about this is that in the worst case, every element will be pushed and popped once.
This gives a time complexity of O(2*N) = O(N).
- Space Complexity: O(N)
If the input was non-increasing, then no element would ever be popped from the stack,
and the stack would grow to a size of N elements at the end.
There are n cars going to the same destination along a one-lane road. The destination is target miles away.
You are given two integer array position and speed, both of length n, where position[i] is the position of the ith car and speed[i] is the speed of the ith car (in miles per hour).
A car can never pass another car ahead of it, but it can catch up to it and drive bumper to bumper at the same speed. The faster car will slow down to match the slower car's speed.
The distance between these two cars is ignored (i.e., they are assumed to have the same position).
A car fleet is some non-empty set of cars driving at the same position and same speed. Note that a single car is also a car fleet.
If a car catches up to a car fleet right at the destination point, it will still be considered as one car fleet.
Return the number of car fleets that will arrive at the destination.
Example 1:
Example 2:
Example 3:
Constraints:
n == position.length == speed.length
1 <= n <= 105
0 < target <= 106
0 <= position[i] < target
All the values of position are unique.
0 < speed[i] <= 106
Approach
Solution
class Solution {
// 1
public int carFleet(int target, int[] position, int[] speed) {
int n = position.length, res = 0;
double[][] cars = new double[n][2];
Complexity Analysis
- Time Complexity:O(NlogN) -> sorting
- Space Complexity: O(N)
Given an array of integers heights representing the histogram's bar height where the width of each bar is 1, return the area of the largest rectangle in the histogram.
Example 1:
Constraints:
Approach
- Monotonic Stack
- store index and height in the stack
- while the top element is greater in height than the new element,
- keep poping the top element and compare the area with maxArea
- start will have the index of the poped element(new element can be extended towards the left)
- push start and height into the stack
- while stack is not empty,
- keep poping and compare the area with maxArea
- return maxArea
Solution
class Solution {
public int largestRectangleArea(int[] heights) {
int maxArea = 0;
Stack<int[]> st = new Stack<>();
for(int i = 0; i < heights.length; i++) {
int start = i;
while(!st.isEmpty() && st.peek()[1] > heights[i]) {
int[] pair = st.pop();
maxArea = Math.max(maxArea, pair[1] * (i-pair[0]));
start = pair[0];
}
st.push(new int[]{start, heights[i]});
}
while(!st.isEmpty()) {
int[] pair = st.pop();
maxArea = Math.max(maxArea, pair[1] * (heights.length-pair[0]));
}
return maxArea;
}
}
Complexity Analysis
- Time Complexity: O(N)
- Space Complexity: O(N)
Resources
Articles
Geeksforgeeks (https://www.geeksforgeeks.org/stack-data-structure/)
A-comprehensive-guide-and-template-for-monotonic-stack-based-problems (https://leetcode.com/discuss/study-guide/2347639/A-comprehensive-guide-and-template-for-
monotonic-stack-based-problems)
Videos
Playlist (https://youtube.com/playlist?list=PL6Zs6LgrJj3vWOf01wMHiTy9IFufptfG3)
Playlist - Hindi (https://youtube.com/playlist?list=PLDzeHZWIZsTrhXYYtx4z8-u8zA-DzuVsj)
Given an array of integers nums which is sorted in ascending order, and an integer target, write a function to search target in nums. If target exists, then return its index. Otherwise,
return -1.
Example 1:
Example 2:
Constraints:
class Solution {
public int search(int[] nums, int target) {
int l = 0, r = nums.length-1;
while(l <= r) {
int mid = l + (r - l)/2;
if(nums[mid] == target)
return mid;
else if(nums[mid] < target)
l = mid + 1;
else
r = mid - 1;
}
return -1;
}
}
Write an efficient algorithm that searches for a value target in an m x n integer matrix matrix. This matrix has the following properties:
Integers in each row are sorted from left to right. The first integer of each row is greater than the last integer of the previous row.
Example 1:
Input: matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 3
Output: true
Example 2:
Constraints:
m == matrix.length
n == matrix[i].length
1 <= m, n <= 100
-104 <= matrix[i][j], target <= 104
Approach
1st:
- keep two pointer one for row, other for column
- initialize tem to point to the last element of the 1st row
- if the element is equal to target then return true
- else if element is < target then move the row pointer downward
- else shift the column pointer to left
2nd:
[It would work only when the element at 1st index of next row should be greater then last element of the previous row]
- left pointer at 0, right at n*m-1 (at last element of the matrix)
- do the binarysearch
- target element can be find using
- rowIndex = mid / number of elements in each row
- colIndex = mid % number of elements in each row
Solution
class Solution {
// worst case go through O(n+m) elements
public boolean searchMatrix(int[][] matrix, int target) {
int m = matrix.length, n = matrix[0].length;
int row = 0, col = n-1;
while(row >= 0 && row < m && col >= 0 && col < n) {
int val = matrix[row][col];
if(val == target)
return true;
else if(val < target)
row++;
else
col--;
}
return false;
}
Complexity Analysis
- Time Complexity:
- 1st approach: O(n+m)
- 2nd approach: O(log(n*m))
- Space Coplexity: O(1) for both approaches
Koko loves to eat bananas. There are n piles of bananas, the ith pile has piles[i] bananas. The guards have gone and will come back in h hours.
Koko can decide her bananas-per-hour eating speed of k. Each hour, she chooses some pile of bananas and eats k bananas from that pile. If the pile has less than k bananas, she
eats all of them instead and will not eat any more bananas during this hour.
Koko likes to eat slowly but still wants to finish eating all the bananas before the guards return.
Return the minimum integer k such that she can eat all the bananas within h hours.
Example 1:
Example 2:
Input: piles = [30,11,23,4,20], h = 5
Output: 30
Example 3:
Constraints:
Approach
- Binary search on range (1, max(pile))
- while the condition satisfies go towards left half
- else go towards right half
Solution
class Solution {
public int minEatingSpeed(int[] piles, int h) {
int left = 1, right = piles[0];
for(int pile : piles) {
if(pile < left)
left = pile;
if(pile > right)
right = pile;
}
int result = right;
while(left <= right) {
int mid = left + (right-left)/2;
if(isSatisfy(piles, mid, h)) {
result = Math.min(result, mid);
right = mid-1;
} else {
left = mid+1;
}
}
return result;
}
Complexity Analysis
- Time Complexity: O(n*logm), m: max(piles)
- Space Complexity: O(1)
33. Search in Rotated Sorted Array
Medium
There is an integer array nums sorted in ascending order (with distinct values).
Prior to being passed to your function, nums is possibly rotated at an unknown pivot index k (1 <= k < nums.length) such that the resulting array is [nums[k], nums[k+1], ..., nums[n-1],
nums[0], nums[1], ..., nums[k-1]] (0-indexed). For example, [0,1,2,4,5,6,7] might be rotated at pivot index 3 and become [4,5,6,7,0,1,2].
Given the array nums after the possible rotation and an integer target, return the index of target if it is in nums, or -1 if it is not in nums.
Example 1:
Example 2:
Example 3:
Constraints:
Approach
Modified Binary Search
Solution
class Solution {
public int search(int[] nums, int target) {
int left = 0, right = nums.length-1;
if(nums[mid] == target)
return mid;
// left sorted portion
if(nums[left] <= nums[mid]) {
if(target < nums[left] || target > nums[mid])
left = mid+1;
else
right = mid-1;
}
// right sorted portion
else {
if(target < nums[mid] || target > nums[right])
right = mid-1;
else
left = mid+1;
}
}
return -1;
}
}
Complexity Analysis
- Time Complexity: O(logN)
- Space Complexity: O(1)
Suppose an array of length n sorted in ascending order is rotated between 1 and n times. For example, the array nums = [0,1,2,4,5,6,7] might become:
Notice that rotating an array [a[0], a[1], a[2], ..., a[n-1]] 1 time results in the array [a[n-1], a[0], a[1], a[2], ..., a[n-2]].
Given the sorted rotated array nums of unique elements, return the minimum element of this array.
Example 1:
Example 2:
Example 3:
Input: nums = [11,13,15,17]
Output: 11
Explanation: The original array was [11,13,15,17] and it was rotated 4 times.
Constraints:
n == nums.length
1 <= n <= 5000
-5000 <= nums[i] <= 5000
All the integers of nums are unique.
nums is sorted and rotated between 1 and n times.
Approach
Modified Binary Search
Solution
class Solution {
public int findMin(int[] nums) {
int n = nums.length;
int start = 0, end = n-1;
int res = 0;
while(start <= end) {
int mid = start + (end - start)/2;
int prev = (mid-1+n)%n, next = (mid+1)%n;
if(nums[mid]<nums[prev] && nums[mid]<nums[next])
return nums[mid];
else if(nums[end] <= nums[mid])
start = mid+1;
else
end = mid-1;
}
return nums[res];
}
}
Complexity Analysis
- Time Complexity: O(logN)
- Space Complexity: O(1)
Design a time-based key-value data structure that can store multiple values for the same key at different time stamps and retrieve the key's value at a certain timestamp.
Example 1:
Input
["TimeMap", "set", "get", "get", "set", "get", "get"]
[[], ["foo", "bar", 1], ["foo", 1], ["foo", 3], ["foo", "bar2", 4], ["foo", 4], ["foo", 5]]
Output
[null, null, "bar", "bar", null, "bar2", "bar2"]
Explanation
TimeMap timeMap = new TimeMap();
timeMap.set("foo", "bar", 1); // store the key "foo" and value "bar" along with timestamp = 1.
timeMap.get("foo", 1); // return "bar"
timeMap.get("foo", 3); // return "bar", since there is no value corresponding to foo at timestamp 3 and timestamp 2, then the
timeMap.set("foo", "bar2", 4); // store the key "foo" and value "bar2" along with timestamp = 4.
timeMap.get("foo", 4); // return "bar2"
timeMap.get("foo", 5); // return "bar2"
Constraints:
Approach
Solution
class TimeMap {
class Pair {
int timestamp;
String value;
public TimeMap() {
mp = new HashMap<>();
}
ans = list.get(index).value;
return ans;
}
/**
* Your TimeMap object will be instantiated and called as such:
* TimeMap obj = new TimeMap();
* obj.set(key,value,timestamp);
* String param_2 = obj.get(key,timestamp);
*/
public class TimeMap {
Complexity Analysis
- Time Complexity:
- Space Complexity:
Given two sorted arrays nums1 and nums2 of size m and n respectively, return the median of the two sorted arrays.
Example 1:
Example 2:
Constraints:
nums1.length == m
nums2.length == n
0 <= m <= 1000
0 <= n <= 1000
1 <= m + n <= 2000
-106 <= nums1[i], nums2[i] <= 106
Approach
Solution
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
if(nums1.length > nums2.length)
return findMedianSortedArrays(nums2, nums1);
int total = nums1.length + nums2.length;
int half = (total + 1) / 2;
int l = 0, r = nums1.length;
double result = 0d;
while(l <= r) {
int i = l + (r - l) / 2;
int j = half - i;
int nums1L = i > 0 ? nums1[i-1]:Integer.MIN_VALUE;
int nums1R = i < nums1.length ? nums1[i]:Integer.MAX_VALUE;
int nums2L = j > 0 ? nums2[j-1]:Integer.MIN_VALUE;
int nums2R = j < nums2.length ? nums2[j]:Integer.MAX_VALUE;
Complexity Analysis
- Time Complexity: O(log(m+n))
- Space Complexity: O(1)
Resources
Articles:
Binary-Search-101-The-Ultimate-Binary-Search-Handbook (https://leetcode.com/problems/binary-search/discuss/423162/Binary-Search-101-The-Ultimate-Binary-Search-
Handbook)
Python-Clear-explanation-Powerful-Ultimate-Binary-Search-Template.-Solved-many-problems. (https://leetcode.com/problems/koko-eating-bananas/discuss/769702/Python-
Clear-explanation-Powerful-Ultimate-Binary-Search-Template.-Solved-many-problems.)
JavaC%2B%2BPython-Binary-Search (https://leetcode.com/problems/koko-eating-bananas/discuss/152324/JavaC%2B%2BPython-Binary-Search)
Binary-Search-for-Beginners-Problems-or-Patterns-or-Sample-solutions (https://leetcode.com/discuss/study-guide/691825/Binary-Search-for-Beginners-Problems-or-Patterns-
or-Sample-solutions)
5-variations-of-Binary-search-(A-Self-Note) (https://leetcode.com/discuss/study-guide/1322500/5-variations-of-Binary-search-(A-Self-Note))
Videos:
Binary Search Introduction (https://youtu.be/P3YID7liBug)
Neetcode Playlist (https://youtube.com/playlist?list=PLot-Xpze53leNZQd0iINpD-MAhMOMzWvO)
Example 1:
Example 2:
Example 3:
Input: head = []
Output: []
Constraints:
Follow up: A linked list can be reversed either iteratively or recursively. Could you
implement both?
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode reverseList(ListNode head) {
ListNode curr = head, next = head, prev = null;
while(curr != null) {
next = curr.next;
curr.next = prev;
prev = curr;
curr = next;
}
return prev;
}
}
You are given the heads of two sorted linked lists list1 and list2.
Merge the two lists in a one sorted list. The list should be made by splicing together the nodes of the first two lists.
Example 1:
Input: list1 = [1,2,4], list2 = [1,3,4]
Output: [1,1,2,3,4,4]
Example 2:
Input: list1 = [], list2 = []
Output: []
Example 3:
Input: list1 = [], list2 = [0]
Output: [0]
Constraints:
The number of nodes in both lists is in the range [0, 50]. -100 <= Node.val <= 100 Both list1 and list2 are sorted in non-decreasing order.
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
ListNode dummy = new ListNode(0);
ListNode result = dummy;
while(list1 != null && list2 != null) {
if(list1.val < list2.val) {
dummy.next = list1;
dummy = dummy.next;
list1 = list1.next;
} else {
dummy.next = list2;
dummy = dummy.next;
list2 = list2.next;
}
}
if(list1 != null) {
dummy.next = list1;
}
if(list2 != null) {
dummy.next = list2;
}
return result.next;
}
}
143. Reorder List
Medium
You are given the head of a singly linked-list. The list can be represented as:
L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → … You may not modify the values in the list's nodes. Only nodes themselves may be changed.
Example 1:
Example 2:
Constraints:
Approach
- Reverse the other half(mid to end)
- 2 pointers one from the head other from the reverse head of other list
- use temp variable to keep the next pointers of both the list
- 1st list's next points to 2nd list & 2nd list's next point to the temp variable containing the next of the 1st list
- move both the pointers
Solution
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public void reorderList(ListNode head) {
ListNode slow = head, fast = head.next;
while(second != null) {
ListNode tmp1 = first.next, tmp2 = second.next;
first.next = second;
second.next = tmp1;
first = tmp1;
second = tmp2;
}
while(curr != null) {
next = curr.next;
curr.next = prev;
prev = curr;
curr = next;
}
return prev;
}
}
Complexity Analysis
- Time Complexity: O(2*N) ~ O(N)
- Space Complexity: O(1)
Given the head of a linked list, remove the nth node from the end of the list and return its head.
Example 1:
Example 2:
Input: head = [1], n = 1
Output: []
Example 3:
Constraints:
1 <= sz <= 30
0 <= Node.val <= 100
1 <= n <= sz
Approach
- 2 pointers approach
- dummy head for so that removing head would be easier
- fast pointer would be ahead by n nodes
- slow and fast will start moving until fast reach the last element
- slow's next node would be the one we need to remove
Solution
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummyHead = new ListNode(0);
dummyHead.next = head;
ListNode slow = dummyHead, fast = dummyHead;
while(n > 0) {
fast = fast.next;
n--;
}
slow.next = slow.next.next;
return dummyHead.next;
}
}
Complexity Analysis
- Time Complexity: O(N) , one pass only
- Space Complexity: O(1)
A linked list of length n is given such that each node contains an additional random pointer, which could point to any node in the list, or null.
Construct a deep copy of the list. The deep copy should consist of exactly n brand new nodes, where each new node has its value set to the value of its corresponding original node.
Both the next and random pointer of the new nodes should point to new nodes in the copied list such that the pointers in the original list and copied list represent the same list state.
None of the pointers in the new list should point to nodes in the original list.
For example, if there are two nodes X and Y in the original list, where X.random --> Y, then for the corresponding two nodes x and y in the copied list, x.random --> y.
The linked list is represented in the input/output as a list of n nodes. Each node is represented as a pair of [val, random_index] where:
Your code will only be given the head of the original linked list.
Example 1:
Example 2:
Example 3:
Constraints:
Approach
- Step 1: Duplicate each node such that old1->new1->old2->new2 ...
- Step 2: Random pointer of new = Random pointer of old's next
- Step 3: Seperate the the nodes to form old1->old2.. & new1->new2..
Solution
/*
// Definition for a Node.
class Node {
int val;
Node next;
Node random;
class Solution {
public Node copyRandomList(Node head) {
if(head == null)
return null;
return newListHead;
}
}
Complexity Analysis
- Time Complexity: O(N+2*N+N) ~ O(N)
- Space Complexity: O(1), no extra memory is used (memory used is for new list only)
2. Add Two Numbers
Medium
You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order, and each of their nodes contains a single digit. Add the two
numbers and return the sum as a linked list.
You may assume the two numbers do not contain any leading zero, except the number 0 itself.
Example 1:
Example 2:
Example 3:
Constraints:
The number of nodes in each linked list is in the range [1, 100].
0 <= Node.val <= 9
It is guaranteed that the list represents a number that does not have leading zeros.
Approach
- Three pointers, one for each given list and 3rd one for resultant list
- untill both the pointers pointing to given lists are null or carry > 0
- add new node to the resultant list
Solution
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode res = new ListNode(0);
ListNode curr1 = l1, curr2 = l2, curr3 = res;
int carry = 0;
while(curr1 != null || curr2 != null || carry > 0) {
int v1 = curr1 == null ? 0 : curr1.val;
int v2 = curr2 == null ? 0 : curr2.val;
int sum = v1 + v2 + carry;
carry = sum / 10;
curr3.next = new ListNode(sum % 10);
curr3 = curr3.next;
curr1 = curr1 == null ? curr1 : curr1.next;
curr2 = curr2 == null ? curr2 : curr2.next;
}
return res.next;
}
}
Complexity Analysis
- Time Complexity: O(max(len(list1, list2))
- Space Complexity: O(max(len(list1, list2))
Given head, the head of a linked list, determine if the linked list has a cycle in it.
There is a cycle in a linked list if there is some node in the list that can be reached again by continuously following the next pointer. Internally, pos is used to denote the index of the
node that tail's next pointer is connected to. Note that pos is not passed as a parameter.
Return true if there is a cycle in the linked list. Otherwise, return false.
Example 1:
Example 2:
Example 3:
Input: head = [1], pos = -1
Output: false
Explanation: There is no cycle in the linked list.
Constraints:
The number of the nodes in the list is in the range [0, 104].
-105 <= Node.val <= 105
pos is -1 or a valid index in the linked-list.
Follow up: Can you solve it using O(1) (i.e. constant) memory?
Approach
- slow and fast pointer
- move fast twice that of slow
- break if fast reach null or fast becomes equal to slow
- if slow == fast, thenn has a cycle otherwise no cycle
Solution
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public boolean hasCycle(ListNode head) {
if(head == null)
return false;
ListNode slow = head, fast = head.next;
Complexity Analysis
- Time Complexity: O(N), N : numbers of nodes in the list
- Space Complexity: O(1)
Given an array of integers nums containing n + 1 integers where each integer is in the range [1, n] inclusive.
There is only one repeated number in nums, return this repeated number.
You must solve the problem without modifying the array nums and uses only constant extra space.
Example 1:
Example 2:
Constraints:
Follow up:
How can we prove that at least one duplicate number must exist in nums?
Can you solve the problem in linear runtime complexity?
Approach
- slow and fast pointer, similar to cycle in link list
Solution
class Solution {
public int findDuplicate(int[] nums) {
slow = nums[0];
while(slow != fast) {
slow = nums[slow];
fast = nums[fast];
}
return slow;
}
}
Complexity Analysis
- Time Complexity: O(N)
- Space Complexity: O(1)
LRUCache(int capacity) Initialize the LRU cache with positive size capacity.
int get(int key) Return the value of the key if the key exists, otherwise return -1.
void put(int key, int value) Update the value of the key if the key exists. Otherwise, add the key-value pair to the cache. If the number of keys exceeds the capacity
from this operation, evict the least recently used key.
The functions get and put must each run in O(1) average time complexity.
Example 1:
Input
["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"]
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
Output
[null, null, null, 1, null, -1, null, -1, 3, 4]
Explanation
LRUCache lRUCache = new LRUCache(2);
lRUCache.put(1, 1); // cache is {1=1}
lRUCache.put(2, 2); // cache is {1=1, 2=2}
lRUCache.get(1); // return 1
lRUCache.put(3, 3); // LRU key was 2, evicts key 2, cache is {1=1, 3=3}
lRUCache.get(2); // returns -1 (not found)
lRUCache.put(4, 4); // LRU key was 1, evicts key 1, cache is {4=4, 3=3}
lRUCache.get(1); // return -1 (not found)
lRUCache.get(3); // return 3
lRUCache.get(4); // return 4
Constraints:
Approach
- Doublely linkedlist, it allows O(1) deletion of a given node
- Map to keep the key mapped to a node, getting the value for a key at O(1) time
- Keeping head and tail of the linked list
- add at head and remove from tail(if size exceeds)
- get method:
- if map doesn't contain the key return -1
- else get the node, remove it, add it (it'll add it to the head of the list), return the value
- put method:
- if map already contains the key, remove the node
- size of map = size, then remove the node at tail
- insert the new node
Solution
/*
* Hepler class
* Node to create doublely linked list
*/
class Node {
int key;
int val;
Node prev;
Node next;
Node(int key, int val) {
this.key = key;
this.val = val;
}
}
class LRUCache {
Node head = new Node(0, 0);
Node tail = new Node(0, 0);
Map<Integer, Node> mp;
int size;
/**
* Your LRUCache object will be instantiated and called as such:
* LRUCache obj = new LRUCache(capacity);
* int param_1 = obj.get(key);
* obj.put(key,value);
*/
Complexity Analysis
- Time Complexity: (on average)
- get() : O(1)
- put() : O(1)
- Space Complexity:
- ~ O(N) for map and doublely linkedlist (over all)
- get() : O(1)
- put() : O(1)
You are given an array of k linked-lists lists, each linked-list is sorted in ascending order.
Merge all the linked-lists into one sorted linked-list and return it.
Example 1:
Example 2:
Input: lists = []
Output: []
Example 3:
Constraints:
k == lists.length
0 <= k <= 104
0 <= lists[i].length <= 500
-104 <= lists[i][j] <= 104
lists[i] is sorted in ascending order.
The sum of lists[i].length will not exceed 104.
Approach
- Create a function to merge two sorted lists
- Use it to merge all the given lists
Sub approach 1:
- we can merge two lists then use the merge list as new list and merge it with next given list
Sub approach 2:
- we can merge all the lists as a group of 2 lists untill we're left with 1 final list
Solution
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
int k = lists.length;
if(k == 0)
return null;
int i = 0;
while(i+1<k) {
ListNode l1 = lists[i], l2 = lists[i+1];
lists[i+1] = merge2LL(l1, l2);
i++;
}
return lists[k-1];
}
if(l1 == null)
tmp.next = l2;
if(l2 == null)
tmp.next = l1;
return dummyHead.next;
}
}
Optimized
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
return partion(lists, 0, lists.length - 1);
}
Complexity Analysis
- Time complexity : O(Nlogk) where k is the number of linked lists.
We can merge two sorted linked list in O(n) time where nn is the total number of nodes in two lists.
Sum up the merge process and we can get: O(Nlogk)
- Space complexity : O(logk) for recursive call stack
We can merge two sorted linked lists in O(1) space.
25. Reverse Nodes in k-Group
(https://leetcode.com/problems/reverse-
nodes-in-k-group/)
Hard
Given the head of a linked list, reverse the nodes of the list k at a time, and return the modified list.
k is a positive integer and is less than or equal to the length of the linked list. If the number of nodes is not a multiple of k then left-out nodes, in the end, should remain as it is.
You may not alter the values in the list's nodes, only nodes themselves may be changed.
Example 1:
Example 2:
Constraints:
Follow-up: Can you solve the problem in O(1) extra memory space?
Approach
- Reusing reverse linkedlist function
- dummy root, it's next point to head of given linkedlist
- use two pointer curr and prev
- storing firstNode of every group
- index to find whether we have the complete group or not, as it determines whether we have reverse the that group or not
- if complete group is there prev.next points to the newly reversed list and
the prev points to firstNode(prev group, which is the last node of the prev group)
- else prev.next points to firstNode
Solution
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
while(curr != null) {
ListNode tail = curr; // keep track of the 1st element of each group
int listIndex = 0;
Complexity Analysis
- Time Complexity: O(n)
- Space Complexity: O(1)
Resources
226. Invert Binary Tree
(https://leetcode.com/problems/invert-binary-
tree/)
Given the root of a binary tree, invert the tree, and return its root.
Example 1:
Input: root = [4,2,7,1,3,6,9]
Output: [4,7,2,9,6,3,1]
Example 2:
Input: root = [2,1,3]
Output: [2,3,1]
Example 3:
Input: root = []
Output: []
Constraints:
Approach
- Recursion
- store one pointer to right or left subtree
- swap left with right and make call recursively
Solution
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public TreeNode invertTree(TreeNode root) {
if(root == null)
return null;
TreeNode tmp = root.right;
root.right = invertTree(root.left);
root.left = invertTree(tmp);
return root;
}
}
Complexity Analysis
- Time Complexity: O(N)
- Space Complexity: O(H), atmost height of tree would be the number of recursive call stack at a given point of time
A binary tree's maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node.
Example 1:
Input: root = [3,9,20,null,null,15,7]
Output: 3
Example 2:
Input: root = [1,null,2]
Output: 2
Constraints:
Approach
- Recursion
- if node = null return 0
- return 1 + max(leftHeight, rightHeight)
Solution
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public int maxDepth(TreeNode root) {
if(root == null)
return 0;
return 1 + Math.max(maxDepth(root.left), maxDepth(root.right));
}
}
Complexity Analysis
- Time Complexity: O(N)
- Space Complexity: O(H), height of the tree
Given the root of a binary tree, return the length of the diameter of the tree.
The diameter of a binary tree is the length of the longest path between any two nodes in a tree. This path may or may not pass through the root.
The length of a path between two nodes is represented by the number of edges between them.
Example 1:
Example 2:
Constraints:
a binary tree in which the left and right subtrees of every node differ in height by no more than 1.
Example 1:
Example 2:
Example 3:
Input: root = []
Output: true
Constraints:
Given the roots of two binary trees p and q, write a function to check if they are the same or not.
Two binary trees are considered the same if they are structurally identical, and the nodes have the same value.
Example 1:
Example 2:
Example 3:
Constraints:
Given the roots of two binary trees root and subRoot, return true if there is a subtree of root with the same structure and node values of subRoot and false otherwise.
A subtree of a binary tree tree is a tree that consists of a node in tree and all of this node's descendants. The tree tree could also be considered as a subtree of itself.
Example 1:
Example 2:
Constraints:
The number of nodes in the root tree is in the range [1, 2000].
The number of nodes in the subRoot tree is in the range [1, 1000].
-104 <= root.val <= 104
-104 <= subRoot.val <= 104
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public boolean isSubtree(TreeNode root, TreeNode subRoot) {
if(root == null && subRoot == null)
return true;
if(root == null || subRoot == null)
return false;
while(!q.isEmpty()) {
TreeNode node = q.poll();
if(node.val == subRoot.val) {
if(isSameTree(node, subRoot))
return true;
}
if(node.left != null)
q.offer(node.left);
if(node.right != null)
q.offer(node.right);
}
return false;
}
Given a binary search tree (BST), find the lowest common ancestor (LCA) of two given nodes in the BST.
According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes p and q as the lowest node in T that has both p and q as descendants
(where we allow a node to be a descendant of itself).”
Example 1:
Input: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
Output: 6
Explanation: The LCA of nodes 2 and 8 is 6.
Example 2:
Constraints:
Approach
- Recursion
- if root's val < p's val & q's val then reduce the problem to right subtree of root
- else if root's val > p's val & q's val then reduce the problem to left subtree of root
- else return root (if p's val or q's val equal to root's val or for p & q lies in different subtree of the root)
Solution
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root == null)
return null;
int val = root.val;
if(val < p.val && val < q.val)
return lowestCommonAncestor(root.right, p, q);
else if(val > p.val && val > q.val)
return lowestCommonAncestor(root.left, p, q);
return root;
}
}
Complexity Analysis
- Time Complexity: O(logN)
- Space Complexity: O(logN) recursive calls
Given the root of a binary tree, return the level order traversal of its nodes' values. (i.e., from left to right, level by level).
Example 1:
Example 2:
Example 3:
Input: root = []
Output: []
Constraints:
Approach
- Use Queue to insert the nodes
- for each level we'll poll node and check if left or right of it is not null then add left or right of it to the queue
Solution
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> result = new ArrayList<>();
if(root == null)
return result;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while(!queue.isEmpty()) {
int levelSize = queue.size();
List<Integer> currLevel = new ArrayList<>(levelSize);
result.add(currLevel);
}
return result;
}
}
Complexity Analysis
- Time Complexity: O(N)
- Space Complexity: O(N), max number of nodes in a level
Given the root of a binary tree, imagine yourself standing on the right side of it, return the values of the nodes you can see ordered from top to bottom.
Example 1:
Example 2:
Input: root = [1,null,3]
Output: [1,3]
Example 3:
Input: root = []
Output: []
Constraints:
Approach
- BFS
- Queue
- add the last element of each level into the result list
Solution
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<Integer> rightSideView(TreeNode root) {
List<Integer> res = new ArrayList<>();
if(root == null)
return res;
while(!queue.isEmpty()) {
int levelSize = queue.size();
for(int i = 0; i < levelSize; i++) {
TreeNode currNode = queue.poll();
if(currNode.left != null)
queue.offer(currNode.left);
if(currNode.right != null)
queue.offer(currNode.right);
if(i == levelSize-1)
res.add(currNode.val);
}
}
return res;
}
}
Complexity Analysis
- Time Complexity: O(N)
- Space Complexity: O(N)
Share Given a binary tree root, a node X in the tree is named good if in the path from root to X there are no nodes with a value greater than X.
Example 1:
Example 2:
Example 3:
Constraints:
The number of nodes in the binary tree is in the range [1, 10^5].
Each node's value is between [-104, 104].
Approach
- check if the node is null
- if node.val >= previously send max, res will be one
- res += left Subtree call with updated max
- res += right Subtree call with updated max
Solution
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public int goodNodes(TreeNode root) {
return goodNodes(root, Integer.MIN_VALUE);
}
Complexity Analysis
- Time Complexity: O(N)
- Space Complexity: O(height)
Given the root of a binary tree, determine if it is a valid binary search tree (BST).
The left subtree of a node contains only nodes with keys less than the node's key. The right subtree of a node contains only nodes with keys greater than the node's key. Both the left
and right subtrees must also be binary search trees.
Example 1:
Example 2:
Input: root = [5,1,4,null,null,3,6]
Output: false
Explanation: The root node's value is 5 but its right child's value is 4.
Constraints:
Approach
- Recursion
- for each node's val we check whether it's in the range (min, max)
- if it fails we return false
- recursively call left and right subtree
- start with (-infinity, +infinity)
- left child -> (min, node.val)
- right child -> (node.val, max)
Solution
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public boolean isValidBST(TreeNode root) {
Long min = Long.MIN_VALUE;
Long max = Long.MAX_VALUE;
Complexity Analysis
- Time Complexity: O(N)
- Space Complexity: O(H), H : height of tree, recursive calls
230. Kth Smallest Element in a BST
Medium
Given the root of a binary search tree, and an integer k, return the kth smallest value (1-indexed) of all the values of the nodes in the tree.
Example 1:
Example 2:
Constraints:
Follow up: If the BST is modified often (i.e., we can do insert and delete operations) and
you need to find the kth smallest frequently, how would you optimize?
Approach
- Recursion
- inorder traversal gives nodes in sorted order of a BST
- ans[] -> store the answer and k in the second index
- decrement ans[1] until it become 0
- when it become zero, that node is the ans
Solution
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public int kthSmallest(TreeNode root, int k) {
int[] ans = new int[2];
ans[1] = k;
inorder(root, ans);
return ans[0];
}
Complexity Analysis
- Time Complexity: O(N)
- Space Complexity: O(N)
Given two integer arrays preorder and inorder where preorder is the preorder traversal of a binary tree and inorder is the inorder traversal of the same tree, construct and return the
binary tree.
Example 1:
Input: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
Output: [3,9,20,null,null,15,7]
Example 2:
Constraints:
Approach
- start and end index
- inorderMap: mapping of inorder array with the index
- if start > end the return null
- root -> node with the preorder val with the preorder index
- root.left -> recursive call, in range (start, inorderMap.get(val)-1)
- root.right -> recursive call, in range (inorderMap.get(val)+1, end)
Solution
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
int preInd;
public TreeNode buildTree(int[] preorder, int[] inorder) {
preInd = 0;
int n = inorder.length;
int startIndex = 0, endIndex = n-1;
Map<Integer, Integer> inorderMap = new HashMap<>();
for(int i = 0; i < n; i++)
inorderMap.put(inorder[i], i);
return helper(preorder, inorder, startIndex, endIndex, inorderMap);
}
public TreeNode helper(int[] preorder, int[] inorder, int startIndex, int endIndex, Map<Integer, Integer> inorderMap) {
if(startIndex > endIndex)
return null;
int val = preorder[preInd++];
TreeNode root = new TreeNode(val);
root.left = helper(preorder, inorder, startIndex, inorderMap.get(val)-1, inorderMap);
root.right = helper(preorder, inorder, inorderMap.get(val)+1, endIndex, inorderMap);
return root;
}
}
Complexity Analysis
- Time Complexity: O(N)
- Space Complexity: O(N)
A path in a binary tree is a sequence of nodes where each pair of adjacent nodes in the sequence has an edge connecting them. A node can only appear in the sequence at most
once. Note that the path does not need to pass through the root.
The path sum of a path is the sum of the node's values in the path.
Given the root of a binary tree, return the maximum path sum of any non-empty path.
Example 1:
Input: root = [1,2,3]
Output: 6
Explanation: The optimal path is 2 -> 1 -> 3 with a path sum of 2 + 1 + 3 = 6.
Example 2:
Constraints:
Approach
- compare max at each node
- left call, right call
- compare max with node's val+left val, node's val+right val, node's val+left val+right val
- return max of node's val, node's val+left val, node's val+right val
Solution
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
int max;
public int maxPathSum(TreeNode root) {
max = -1001;
helper(root);
return max;
}
Complexity Analysis
- Time Complexity: O(n)
- Space Complexity: O(logn), recursive call stacks
Hard
Serialization is the process of converting a data structure or object into a sequence of bits so that it can be stored in a file or memory buffer, or transmitted across a network
connection link to be reconstructed later in the same or another computer environment.
Design an algorithm to serialize and deserialize a binary tree. There is no restriction on how your serialization/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.
Clarification: The input/output format is the same as how LeetCode serializes a binary tree. You do not necessarily need to follow this format, so please be creative and come up with
different approaches yourself.
Example 1:
Example 2:
Input: root = []
Output: []
Constraints:
Approach
Solution
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Codec {
return root;
}
}
// Your Codec object will be instantiated and called as such:
// Codec ser = new Codec();
// Codec deser = new Codec();
// TreeNode ans = deser.deserialize(ser.serialize(root));
Complexity Analysis
- Time Complexity: O(N)
- Space Complexity: O(N)
Tree
Patterns
BFS
DFS (Preorder, Inorder & Postorder)
BFS
Here are the steps of our algorithm:
Given the root of a binary tree, return the level order traversal of its nodes' values. (i.e., from left to right, level by level).
Example 1:
Example 2:
Example 3:
Input: root = []
Output: []
Constraints:
import java.util.*;
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) {
val = x;
}
};
class Main {
public static List<List<Integer>> traverse(TreeNode root) {
List<List<Integer>> result = new ArrayList<List<Integer>>();
if (root == null)
return result;
return result;
}
Time complexity
The time complexity of the above algorithm is O(N), where ‘N’ is the total number of nodes in the tree. This is due to the fact that we traverse each node once.
Space complexity
The space complexity of the above algorithm will be O(N) as we need to return a list containing the level order traversal. We will also need O(N) space for the queue. Since we can
have a maximum of N/2 nodes at any level (this could happen only at the lowest level), therefore we will need O(N) space to store them in the queue.
DFS
Inorder(tree)
import java.util.*;
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) {
val = x;
}
};
class Main {
public static void traverse(TreeNode root) {
if (root == null)
return;
traverse(root.left);
System.out.println(root.val);
traverse(root.right);
}
Time complexity
The time complexity of the above algorithm is O(N), where ‘N’ is the total number of nodes in the tree. This is due to the fact that we traverse each node once.
Space complexity
The space complexity of the above algorithm will be O(H) where H is the height of the tree, needed for recursive call stacks.
208. Implement Trie (Prefix Tree)
(https://leetcode.com/problems/implement-
trie-prefix-tree/)
Medium
A trie (pronounced as "try") or prefix tree is a tree data structure used to efficiently store and retrieve keys in a dataset of strings. There are various applications of this data structure,
such as autocomplete and spellchecker.
Example 1:
Input
["Trie", "insert", "search", "search", "startsWith", "insert", "search"]
[[], ["apple"], ["apple"], ["app"], ["app"], ["app"], ["app"]]
Output
[null, null, true, false, true, null, true]
Explanation
Trie trie = new Trie();
trie.insert("apple");
trie.search("apple"); // return True
trie.search("app"); // return False
trie.startsWith("app"); // return True
trie.insert("app");
trie.search("app"); // return True
Constraints:
Approach
26 links, end marker
[ , , ...26]
/ . . . 26 \ /..26..\
Solution
class Trie {
TrieNode root;
public Trie() {
root = new TrieNode();
}
if(curr.node[ind] != null) {
curr = curr.node[ind];
} else {
curr.node[ind] = new TrieNode();
curr = curr.node[ind];
}
}
curr.end = true;
}
class TrieNode {
TrieNode[] node = new TrieNode[26];
boolean end;
}
/**
* Your Trie object will be instantiated and called as such:
* Trie obj = new Trie();
* obj.insert(word);
* boolean param_2 = obj.search(word);
* boolean param_3 = obj.startsWith(prefix);
*/
Complexity Analysis
- Time Complexity:
- insert: O(m), where m is the key length.
- search: O(m)
- startsWith: O(m)
- Space Complexity:
- insert: O(m)
- search: O(1)
- startsWith: O(1)
Design a data structure that supports adding new words and finding if a string matches any previously added string.
Example:
Input
["WordDictionary","addWord","addWord","addWord","search","search","search","search"]
[[],["bad"],["dad"],["mad"],["pad"],["bad"],[".ad"],["b.."]]
Output
[null,null,null,null,false,true,true,true]
Explanation
WordDictionary wordDictionary = new WordDictionary();
wordDictionary.addWord("bad");
wordDictionary.addWord("dad");
wordDictionary.addWord("mad");
wordDictionary.search("pad"); // return False
wordDictionary.search("bad"); // return True
wordDictionary.search(".ad"); // return True
wordDictionary.search("b.."); // return True
Constraints:
Approach
- Use Trie
Solution
class WordDictionary {
TrieNode root;
public WordDictionary() {
root = new TrieNode();
}
if (curr.node[ind] != null) {
curr = curr.node[ind];
} else {
curr.node[ind] = new TrieNode();
curr = curr.node[ind];
}
}
curr.end = true;
}
class TrieNode {
TrieNode[] node = new TrieNode[26];
boolean end;
}
}
/**
* Your WordDictionary object will be instantiated and called as such:
* WordDictionary obj = new WordDictionary();
* obj.addWord(word);
* boolean param_2 = obj.search(word);
*/
Complexity Analysis
- Time Complexity:
- Space Complexity:
Resources
703. Kth Largest Element in a Stream
Easy
Design a class to find the kth largest element in a stream. Note that it is the kth largest element in the sorted order, not the kth distinct element.
KthLargest(int k, int[] nums) Initializes the object with the integer k and the stream of integers nums.
int add(int val) Appends the integer val to the stream and returns the element representing the kth largest element in the stream.
Example 1:
Input
["KthLargest", "add", "add", "add", "add", "add"]
[[3, [4, 5, 8, 2]], [3], [5], [10], [9], [4]]
Output
[null, 4, 5, 5, 8, 8]
Explanation
Constraints:
while(pq.size() > k)
pq.poll();
}
return pq.peek();
}
}
/**
* Your KthLargest object will be instantiated and called as such:
* KthLargest obj = new KthLargest(k, nums);
* int param_1 = obj.add(val);
*/
You are given an array of integers stones where stones[i] is the weight of the ith stone.
We are playing a game with the stones. On each turn, we choose the heaviest two stones and smash them together. Suppose the heaviest two stones have weights x and y with x <=
y. The result of this smash is:
If x == y, both stones are destroyed, and If x != y, the stone of weight x is destroyed, and the stone of weight y has new weight y - x. At the end of the game, there is at most one stone
left.
Return the smallest possible weight of the left stone. If there are no stones left, return 0.
Example 1:
Example 2:
Constraints:
while(pq.size() > 1) {
int x = pq.poll();
int y = pq.poll();
if(x != y) {
pq.offer(x-y); // abs not rqd as x would always be greater than equal to y
}
}
return pq.isEmpty()?0:pq.peek();
}
}
Given an array of points where points[i] = [xi, yi] represents a point on the X-Y plane and an integer k, return the k closest points to the origin (0, 0).
The distance between two points on the X-Y plane is the Euclidean distance (i.e., √(x1 - x2)2 + (y1 - y2)2).
You may return the answer in any order. The answer is guaranteed to be unique (except for the order that it is in).
Example 1:
Example 2:
Constraints:
Approach
- Have a Max PriorityQueue based on euclidean distance
- add each point to PQ, if size > k then poll
- remaining points inside the PQ is the answer
Solution
class Solution {
public int[][] kClosest(int[][] points, int k) {
int[][] res = new int[k][2];
PriorityQueue<Point> pq = new PriorityQueue<Point>((a, b) -> new Double(b.dist).compareTo(new Double(a.dist)));
class Point {
int x;
int y;
double dist;
Point(int x, int y) {
this.x = x;
this.y = y;
dist = Math.pow(x*x + y*y, 0.5);
}
}
class Solution {
public int[][] kClosest(int[][] points, int k) {
int[][] res = new int[k][2];
PriorityQueue<int[]> pq = new PriorityQueue<int[]>((a, b) -> (b[0]*b[0] + b[1]*b[1]) - (a[0]*a[0] + a[1]*a[1]));
Complexity Analysis
- Time Complexity: O(nlogk) -> Adding to/removing from the heap (or priority queue)
only takes O(\log k) time when the size of the heap is capped at k elements.
- Space Complexity: O(k) -> The heap (or priority queue) will contain at most kk elements.
Given an integer array nums and an integer k, return the kth largest element in the array.
Note that it is the kth largest element in the sorted order, not the kth distinct element.
Example 1:
Example 2:
Constraints:
Approach
- Min PriorityQueue
- if size becomes > k, poll
- after going through the array, we'll have the kth largest element as the min element in the PQ
Solution
class Solution {
public int findKthLargest(int[] nums, int k) {
PriorityQueue<Integer> pq = new PriorityQueue<>((a,b)->a-b);
for(int num : nums) {
pq.offer(num);
if(pq.size() > k)
pq.poll();
}
return pq.peek();
}
}
Complexity Analysis
- Time Complexity: O(nlogk)
- Space Complexity: O(k)
TODO
Quick Select
Given a characters array tasks, representing the tasks a CPU needs to do, where each letter represents a different task. Tasks could be done in any order. Each task is done in one
unit of time. For each unit of time, the CPU could complete either one task or just be idle.
However, there is a non-negative integer n that represents the cooldown period between two same tasks (the same letter in the array), that is that there must be at least n units of
time between any two same tasks.
Return the least number of units of times that the CPU will take to finish all the given tasks.
Example 1:
Example 2:
Example 3:
Constraints:
Approach
Solution
class Solution {
public int leastInterval(char[] tasks, int n) {
int[] freq = new int[26];
int max = 0; // keep the max value
int maxCount = 0; // number of tasks with the max value
Complexity Analysis
- Time Complexity: O(N)
- Space Complexity: O(26)
The median is the middle value in an ordered integer list. If the size of the list is even, there is no middle value and the median is the mean of the two middle values.
For example, for arr = [2,3,4], the median is 3. For example, for arr = [2,3], the median is (2 + 3) / 2 = 2.5. Implement the MedianFinder class:
MedianFinder() initializes the MedianFinder object. void addNum(int num) adds the integer num from the data stream to the data structure. double findMedian() returns the median of
all elements so far. Answers within 10-5 of the actual answer will be accepted.
Example 1:
Input
["MedianFinder", "addNum", "addNum", "findMedian", "addNum", "findMedian"]
[[], [1], [2], [], [3], []]
Output
[null, null, null, 1.5, null, 2.0]
Explanation
MedianFinder medianFinder = new MedianFinder();
medianFinder.addNum(1); // arr = [1]
medianFinder.addNum(2); // arr = [1, 2]
medianFinder.findMedian(); // return 1.5 (i.e., (1 + 2) / 2)
medianFinder.addNum(3); // arr[1, 2, 3]
medianFinder.findMedian(); // return 2.0
Constraints:
Follow up:
If all integer numbers from the stream are in the range [0, 100], how would you optimize your solution?
If 99% of all integer numbers from the stream are in the range [0, 100], how would you optimize your solution?
Approach
- Use two heaps, one max heap(smallerList), other min heap(largerList)
- if smallList is not empty and first element is less than equal to num then add num to largeList
- else add num to smallList
- balance the size of both the heaps
- so that smallList never become more than 1 + size of largeList
- largeList's size always remain less or equal to the size of smallList
Solution
class MedianFinder {
int size;
PriorityQueue<Integer> smallList;
PriorityQueue<Integer> largeList;
public MedianFinder() {
smallList = new PriorityQueue<>(Collections.reverseOrder()); // maxHeap
largeList = new PriorityQueue<>(); // minHeap
}
if(size % 2 != 0) {
return (double) smallList.peek();
} else {
return (double) (smallList.peek() + largeList.peek())/2.0;
}
}
}
/**
* Your MedianFinder object will be instantiated and called as such:
* MedianFinder obj = new MedianFinder();
* obj.addNum(num);
* double param_2 = obj.findMedian();
*/
Complexity Analysis
- Time Complexity:
- add operation: O(logN)
- find median operation: O(1)
- Space Complexity:
- add operation: O(1)
- find median operation: O(1)
Resources
78. Subsets
(https://leetcode.com/problems/subsets/)
Medium
Given an integer array nums of unique elements, return all possible subsets (the power set).
The solution set must not contain duplicate subsets. Return the solution in any order.
Example 1:
Example 2:
Constraints:
Approach
Backtracking:
- Either select the element or not
- recursive call
tmp.add(nums[index]);
backtrack(nums, index+1, tmp, ans);
tmp.remove(tmp.size()-1);
backtrack(nums, index+1, tmp, ans);
Solution
class Solution {
public List<List<Integer>> subsets(int[] nums) {
List<Integer> tmp = new ArrayList<>();
List<List<Integer>> ans = new ArrayList<>();
backtrack(nums, 0, tmp, ans);
return ans;
}
private void backtrack(int[] nums, int index, List<Integer> tmp, List<List<Integer>> ans) {
if(index > nums.length)
return;
if(index == nums.length) {
ans.add(new ArrayList<>(tmp));
return;
}
tmp.add(nums[index]);
backtrack(nums, index+1, tmp, ans);
tmp.remove(tmp.size()-1);
backtrack(nums, index+1, tmp, ans);
}
}
Complexity Analysis
- Time Complexity: O(2^N)
- Space Complexity: O(N)
39. Combination Sum
(https://leetcode.com/problems/combination-
sum/)
Medium
Given an array of distinct integers candidates and a target integer target, return a list of all unique combinations of candidates where the chosen numbers sum to target. You may
return the combinations in any order.
The same number may be chosen from candidates an unlimited number of times. Two combinations are unique if the frequency of at least one of the chosen numbers is different.
It is guaranteed that the number of unique combinations that sum up to target is less than 150 combinations for the given input.
Example 1:
Example 2:
Example 3:
Constraints:
Approach
Backtrack:
- We can choose any of the element present in the array(n choices)
- In subsets, we have only 2 choices
- Looping through elements to create a n way recursive call
for(int i = index; i < nums.length; i++) {
tmp.add(nums[i]);
backtrack(nums, i, tmp, ans, target - nums[i]);
tmp.remove(tmp.size()-1);
}
Solution
class Solution {
public List<List<Integer>> combinationSum(int[] candidates, int target) {
List<List<Integer>> res = new ArrayList<>();
backtrack(candidates, 0, new ArrayList<>(), res, target);
return res;
}
private void backtrack(int[] nums, int index, List<Integer> tmp, List<List<Integer>> ans, int target) {
if(index >= nums.length || target < 0)
return;
if(target == 0) {
ans.add(new ArrayList<>(tmp));
return;
}
Complexity Analysis
- Time Complexity: O(N^N)
- Space Complexity: O(N)
46. Permutations
(https://leetcode.com/problems/permutations/)
Medium
Given an array nums of distinct integers, return all the possible permutations. You can return the answer in any order.
Example 1:
Example 2:
Example 3:
Constraints:
Approach
- we have n choices initially, after each selection we can't take that element again
- take a mark array to keep track of what elements fron the nums array which are already select in the current path
for(int i = 0; i < nums.length; i++) {
if(mark[i] == false) {
mark[i] = true;
tmp.add(nums[i]);
backtrack(nums, mark, tmp, ans);
tmp.remove(tmp.size()-1);
mark[i] = false;
}
}
Solution
class Solution {
public List<List<Integer>> permute(int[] nums) {
boolean[] mark = new boolean[nums.length];
List<List<Integer>> ans = new ArrayList<>();
backtrack(nums, mark, new ArrayList<>(), ans);
return ans;
}
private void backtrack(int[] nums, boolean[] mark, List<Integer> tmp, List<List<Integer>> ans) {
if(tmp.size() == nums.length) {
ans.add(new ArrayList<>(tmp));
return;
}
Complexity Analysis
- Time Complexity: O(N^N)
- Space Complexity: O(N)
90. Subsets II
(https://leetcode.com/problems/subsets-ii/)
Medium
Given an integer array nums that may contain duplicates, return all possible subsets (the power set).
The solution set must not contain duplicate subsets. Return the solution in any order.
Example 1:
Constraints:
Approach
Ref: 1.Subsets (https://github.com/dipjul/NeetCode-150/blob/13aea2145a56c73ef5e1b8ea0b5cbe94745415e9/10.%20Backtracking/1.Subsets.md)
Same as Subsets
- to skip duplicates, before making the 2nd backtracking call we check the current and next element
- while those are equal we keep skipping to the next index
Solution
class Solution {
public List<List<Integer>> subsetsWithDup(int[] nums) {
List<List<Integer>> ans = new ArrayList<>();
Arrays.sort(nums);
backtrack(nums, 0, new ArrayList<>(), ans);
return ans;
}
private void backtrack(int[] nums, int index, List<Integer> tmp, List<List<Integer>> ans) {
if(index > nums.length)
return;
if(index == nums.length) {
ans.add(new ArrayList<>(tmp));
return;
}
tmp.add(nums[index]);
backtrack(nums, index+1, tmp, ans);
tmp.remove(tmp.size()-1);
while(index+1 < nums.length && nums[index] == nums[index+1])
index++;
backtrack(nums, index+1, tmp, ans);
}
}
Complexity Analysis
- Time Complexity: O(2^N)
- Space Complexity: O(N)
Given a collection of candidate numbers (candidates) and a target number (target), find all unique combinations in candidates where the candidate numbers sum to target.
Each number in candidates may only be used once in the combination.
Example 1:
Example 2:
Constraints:
Approach
Ref: 2.Combination Sum (https://github.com/dipjul/NeetCode-150/blob/76226b171098f898f8263acd34b2d3236d30f471/10.%20Backtracking/2.CombinationSum.md)
Solution
class Solution {
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
List<List<Integer>> ans = new ArrayList<>();
Arrays.sort(candidates);
backtrack(candidates, 0, target, new ArrayList<>(), ans);
return ans;
}
private void backtrack(int[] nums, int index, int target, List<Integer> tmp, List<List<Integer>> ans) {
if(target == 0) {
ans.add(new ArrayList<>(tmp));
return;
}
if(index >= nums.length || target < 0)
return;
tmp.add(nums[index]);
backtrack(nums, index+1, target-nums[index], tmp, ans);
tmp.remove(tmp.size()-1);
while(index+1 < nums.length && nums[index] == nums[index+1])
index++;
backtrack(nums, index+1, target, tmp, ans);
}
}
Complexity Analysis
- Time Complexity: O(2^N)
- Space Complexity: O(N)
Given an m x n grid of characters board and a string word, return true if word exists in the grid.
The word can be constructed from letters of sequentially adjacent cells, where adjacent cells are horizontally or vertically neighboring. The same letter cell may not be used more than
once.
Example 1:
Example 2:
Example 3:
Constraints:
m == board.length
n = board[i].length
1 <= m, n <= 6
1 <= word.length <= 15
board and word consists of only lowercase and uppercase English letters.
Follow up: Could you use search pruning to make your solution faster with a larger board?
Approach
Backtracking:
- 4 choices top, down, left & right moves
- mark the element we are accessing
- if we match the word, we get the ans
Solution
class Solution {
public boolean exist(char[][] board, String word) {
boolean[] res = new boolean[1];
boolean[][] mark = new boolean[board.length][board[0].length];
for(int i = 0; i < board.length; i++) {
for(int j = 0; j < board[0].length; j++) {
if(board[i][j] == word.charAt(0)) {
backtrack(board, word, mark, i, j, res);
if(res[0] == true)
return true;
}
}
}
return false;
}
private void backtrack(char[][] board, String word, boolean[][] mark, int i, int j, boolean[] res) {
if (word.length() == 0) {
res[0] = true;
return;
}
if (i >= board.length || j >= board[0].length || i < 0 || j < 0 || mark[i][j])
return;
if (word.charAt(0) == board[i][j]) {
mark[i][j] = true;
if (i >= 0) {
backtrack(board, word.substring(1), mark, i - 1, j, res);
}
if (j >= 0) {
backtrack(board, word.substring(1), mark, i, j - 1, res);
}
if (i < board.length) {
backtrack(board, word.substring(1), mark, i + 1, j, res);
}
if (j < board[0].length) {
backtrack(board, word.substring(1), mark, i, j + 1, res);
}
mark[i][j] = false;
}
}
}
// little optimized
class Solution {
boolean[][] visited;
public boolean exist(char[][] board, String word) {
int rows = board.length;
int cols = board[0].length;
visited = new boolean[rows][cols];
public boolean search(int i, int j, int index, String word, char[][] board) {
if(index == word.length())
return true;
if(i < 0 || i >= board.length || j < 0 || j >= board[0].length || word.charAt(index) != board[i][j] || visited[i][j]) {
return false;
}
visited[i][j] = true;
if(
search(i+1, j, index+1, word, board) ||
search(i-1, j, index+1, word, board) ||
search(i, j+1, index+1, word, board) ||
search(i, j-1, index+1, word, board)
) {
return true;
}
visited[i][j] = false;
return false;
}
}
Complexity Analysis
- Time Complexity: O(4^N)
- Space Complexity: O(N)
Given a string s, partition s such that every substring of the partition is a palindrome. Return all possible palindrome partitioning of s.
Example 1:
Input: s = "aab"
Output: [["a","a","b"],["aa","b"]]
Example 2:
Input: s = "a"
Output: [["a"]]
Constraints:
Approach
- backtracking
- go through all possible combination of substring
- if the substring is palindrome add it to the tmp result and backtrack
- if substring becomes empty then add tmp result to the result
Solution
class Solution {
public List<List<String>> partition(String s) {
List<List<String>> result = new ArrayList();
helper(s, new ArrayList<String>(), result);
return result;
}
Complexity Analysis
- Time Complexity: O(N*2^N)
- Space Complexity: O(N)
Given a string containing digits from 2-9 inclusive, return all possible letter combinations that the number could represent. Return the answer in any order.
A mapping of digit to letters (just like on the telephone buttons) is given below. Note that 1 does not map to any letters.
Example 1:
Example 2:
Example 3:
Constraints:
Approach
Backtrack:
char chs[] = mp.get(str.charAt(i));
for(int j = 0; j < chs.length; j++) {
recursive(str, i+1, s+chs[j], res); - stmt
}
stmt is equivalent to:
String s = s+chs[j];
recursive(str, i+1, s, res);
s = s.substring(0,s.length()-1);
Solution
class Solution {
Map<Character, char[]> mp;
public List<String> letterCombinations(String digits) {
if(digits.equals(""))
return new ArrayList<>();
mp = new HashMap<>();
mp.put('2', new char[]{'a', 'b', 'c'});
mp.put('3', new char[]{'d', 'e', 'f'});
mp.put('4', new char[]{'g', 'h', 'i'});
mp.put('5', new char[]{'j', 'k', 'l'});
mp.put('6', new char[]{'m', 'n', 'o'});
mp.put('7', new char[]{'p', 'q', 'r', 's'});
mp.put('8', new char[]{'t', 'u', 'v'});
mp.put('9', new char[]{'w', 'x', 'y', 'z'});
List<String> res = new ArrayList<>();
recursive(digits, 0, "", res);
return res;
}
}
}
Complexity Analysis
- Time Complexity:
- Space Complexity:
51. N-Queens
(https://leetcode.com/problems/n-queens/)
Hard
The n-queens puzzle is the problem of placing n queens on an n x n chessboard such that no two queens attack each other.
Given an integer n, return all distinct solutions to the n-queens puzzle. You may return the answer in any order.
Each solution contains a distinct board configuration of the n-queens' placement, where 'Q' and '.' both indicate a queen and an empty space, respectively.
Example 1:
Input: n = 4
Output: [[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]]
Explanation: There exist two distinct solutions to the 4-queens puzzle as shown above
Example 2:
Input: n = 1
Output: [["Q"]]
Constraints:
1 <= n <= 9
Approach
- Backtracking
- Used 3 boolean arrays to mark row, left diagonal and rightdiagonal
- r-c could be -ve so we add the n-1 to it
- for each column,
- we go through each row and check whether we can place the queen or not
- if possible then we place the column index at the row[]
- recursive call to next column
Solution
// Do not try this at home
class Solution {
int[] row;
boolean[] rw, ld, rd;
public List<List<String>> solveNQueens(int n) {
row = new int[n];
rw = new boolean[n];
ld = new boolean[2*n-1];
rd = new boolean[2*n-1];
List<List<String>> ans = new ArrayList<>();
backtrack(0, n, ans);
return ans;
}
Complexity Analysis
- Time Complexity: O(n!)
- Space Complexity: O(n^2), building the result
Resources
200. Number of Islands
(https://leetcode.com/problems/number-of-
islands/)
Medium
Given an m x n 2D binary grid grid which represents a map of '1's (land) and '0's (water), return 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 the grid are all surrounded by water.
Example 1:
Input: grid = [
["1","1","1","1","0"],
["1","1","0","1","0"],
["1","1","0","0","0"],
["0","0","0","0","0"]
]
Output: 1
Example 2:
Input: grid = [
["1","1","0","0","0"],
["1","1","0","0","0"],
["0","0","1","0","0"],
["0","0","0","1","1"]
]
Output: 3
Constraints:
m == grid.length
n == grid[i].length
1 <= m, n <= 300
grid[i][j] is '0' or '1'.
Approach
- DFS
- number of time DFS called is the ans
Soluiton
class Solution {
public int numIslands(char[][] grid) {
boolean[][] mark = new boolean[grid.length][grid[0].length];
int res = 0;
for(int i = 0; i < grid.length; i++) {
for(int j = 0; j < grid[0].length; j++) {
if(!mark[i][j] && grid[i][j] == '1') {
res++;
dfs(grid, i, j, mark);
}
}
}
return res;
}
Complexity Analysis
- Time Complexity: O(n*m)
- Space Complexity: O(n*m)
Each node in the graph contains a value (int) and a list (List[Node]) of its neighbors.
class Node {
public int val;
public List<Node> neighbors;
}
For simplicity, each node's value is the same as the node's index (1-indexed). For example, the first node with val == 1, the second node with val == 2, and so on. The graph is
represented in the test case using an adjacency list.
An adjacency list is a collection of unordered lists used to represent a finite graph. Each list describes the set of neighbors of a node in the graph.
The given node will always be the first node with val = 1. You must return the copy of the given node as a reference to the cloned graph.
Example 1:
Input: adjList = [[2,4],[1,3],[2,4],[1,3]]
Output: [[2,4],[1,3],[2,4],[1,3]]
Explanation: There are 4 nodes in the graph.
1st node (val = 1)'s neighbors are 2nd node (val = 2) and 4th node (val = 4).
2nd node (val = 2)'s neighbors are 1st node (val = 1) and 3rd node (val = 3).
3rd node (val = 3)'s neighbors are 2nd node (val = 2) and 4th node (val = 4).
4th node (val = 4)'s neighbors are 1st node (val = 1) and 3rd node (val = 3).
Example 2:
Example 3:
Input: adjList = []
Output: []
Explanation: This an empty graph, it does not have any nodes.
Constraints:
Approach
Solution
/*
// Definition for a Node.
class Node {
public int val;
public List<Node> neighbors;
public Node() {
val = 0;
neighbors = new ArrayList<Node>();
}
public Node(int _val) {
val = _val;
neighbors = new ArrayList<Node>();
}
public Node(int _val, ArrayList<Node> _neighbors) {
val = _val;
neighbors = _neighbors;
}
}
*/
class Solution {
while (!q.isEmpty()) {
Node curr = q.poll();
set.add(curr);
return mp.get(node.val);
}
}
Complexity Analysis
- Time Complexity: O(n*m)
- Space Complexity: O(n+m)
You are given an m x n binary matrix grid. An island is a group of 1's (representing land) connected 4-directionally (horizontal or vertical.) You may assume all four edges of the grid
are surrounded by water.
The area of an island is the number of cells with a value 1 in the island.
Example 1:
Input: grid = [
[0,0,1,0,0,0,0,1,0,0,0,0,0],
[0,0,0,0,0,0,0,1,1,1,0,0,0],
[0,1,1,0,1,0,0,0,0,0,0,0,0],
[0,1,0,0,1,1,0,0,1,0,1,0,0],
[0,1,0,0,1,1,0,0,1,1,1,0,0],
[0,0,0,0,0,0,0,0,0,0,1,0,0],
[0,0,0,0,0,0,0,1,1,1,0,0,0],
[0,0,0,0,0,0,0,1,1,0,0,0,0]]
Output: 6
Explanation: The answer is not 11, because the island must be connected 4-directionally.
Example 2:
Constraints:
m == grid.length
n == grid[i].length
1 <= m, n <= 50
grid[i][j] is either 0 or 1.
Approach
- DFS
- count number of dfs call inside
Solution
class Solution {
public int maxAreaOfIsland(int[][] grid) {
boolean[][] mark = new boolean[grid.length][grid[0].length];
int res = 0;
Complexity Analysis
- Time Complexity: O(n*m)
- Space Complexity: O(n*m)
There is an m x n rectangular island that borders both the Pacific Ocean and Atlantic Ocean. The Pacific Ocean touches the island's left and top edges, and the Atlantic Ocean
touches the island's right and bottom edges.
The island is partitioned into a grid of square cells. You are given an m x n integer matrix heights where heights[r][c] represents the height above sea level of the cell at coordinate (r,
c).
The island receives a lot of rain, and the rain water can flow to neighboring cells directly north, south, east, and west if the neighboring cell's height is less than or equal to the current
cell's height. Water can flow from any cell adjacent to an ocean into the ocean.
Return a 2D list of grid coordinates result where result[i] = [ri, ci] denotes that rain water can flow from cell (ri, ci) to both the Pacific and Atlantic oceans.
Example 1:
Example 2:
Constraints:
m == heights.length
n == heights[r].length
1 <= m, n <= 200
0 <= heights[r][c] <= 105
Approach
- dfs: start from all the boundary along with respective set for pacific and atlantic
- intersection of both set
Solution
class Solution {
private void dfs(int[][] grid, int i, int j, Set<String> visited, int prev) {
if (i < 0 || j < 0 || i >= grid.length || j >= grid[0].length || grid[i][j] < prev || visited.contains(i + "," + j)) return;
Complexity Analysis
- Time Complexity: O(m*n)
- Space Complexity: O(m*n)
Given an m x n matrix board containing 'X' and 'O', capture all regions that are 4-directionally surrounded by 'X'.
A region is captured by flipping all 'O's into 'X's in that surrounded region.
Example 1:
Input: board = [
["X","X","X","X"],
["X","O","O","X"],
["X","X","O","X"],
["X","O","X","X"]]
Output: [
["X","X","X","X"],
["X","X","X","X"],
["X","X","X","X"],
["X","O","X","X"]]
Explanation: Surrounded regions should not be on the border, which means that any 'O' on the border of the board are not flipped to
Example 2:
Constraints:
m == board.length
n == board[i].length
1 <= m, n <= 200
board[i][j] is 'X' or 'O'.
Approach
- start dfs from all the boundaries
- mark all the cells that can be reach from the dfs as 1
- all those which were not marked 1 and in give board is "0", set them "X"
Solution
class Solution {
public void solve(char[][] board) {
int[][] mark = new int[board.length][board[0].length];
for (int j = 0; j < board[0].length; j++) {
if (board[0][j] == 'O')
dfs(board, 0, j, mark);
}
for (int j = 0; j < board[0].length; j++) {
if (board[board.length - 1][j] == 'O')
dfs(board, board.length - 1, j, mark);
}
for (int j = 0; j < board.length; j++) {
if (board[j][0] == 'O')
dfs(board, j, 0, mark);
}
for (int j = 0; j < board.length; j++) {
if (board[j][board[0].length - 1] == 'O')
dfs(board, j, board[0].length - 1, mark);
}
for(int i = 0; i < board.length; i++) {
for(int j = 0; j < board[0].length; j++) {
if(mark[i][j] == 0 && board[i][j] == 'O')
board[i][j] = 'X';
}
}
}
Complexity Analysis
- Time Complexity: O(m*n)
- Space Complexity: O(m*n)
You are given an m x n grid where each cell can have one of three values:
Every minute, any fresh orange that is 4-directionally adjacent to a rotten orange becomes rotten.
Return the minimum number of minutes that must elapse until no cell has a fresh orange. If this is impossible, return -1.
Example 1:
Example 2:
Example 3:
Constraints:
m == grid.length
n == grid[i].length
1 <= m, n <= 10
grid[i][j] is 0, 1, or 2.
Approaches
- Implementation of Topological Sort
- Insert all the rotten tomatoes inside the queue as sources
- have an fresh tomato count
- while sources queue not empty,
- we pull one pos at a time and check it's neighbour if there is any fresh tomato
- if we found fresh tomato, we make it rotten and add to our sources queue, decrement the fresh count
- for each run of while loop,
- we check if the sources is not empty, increment the time
Solution
class Solution {
public int orangesRotting(int[][] grid) {
int[][] dirs = {{-1, 0}, {1, 0}, {0, -1}, {0, 1} };
Queue<int[]> q = new LinkedList<>();
int n = grid.length, m = grid[0].length;
int countFresh = 0;
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++) {
if(grid[i][j] == 1)
countFresh++;
if(grid[i][j] == 2)
q.offer(new int[]{i, j});
}
}
if(countFresh == 0) return 0;
int time = 0;
while(!q.isEmpty()) {
int size = q.size();
for(int i = 0; i < size; i++) {
int[] currPos = q.poll();
int currI = currPos[0], currJ = currPos[1];
for(int[] dir : dirs) {
if(currI+dir[0] < 0 || currJ+dir[1] < 0 || currI+dir[0] >= n || currJ+dir[1] >= m || grid[currI+dir[0]][currJ+dir
continue;
if(grid[currI+dir[0]][currJ+dir[1]] == 1) {
grid[currI+dir[0]][currJ+dir[1]] = 2;
q.offer(new int[]{currI+dir[0], currJ+dir[1]});
countFresh--;
}
}
}
if(!q.isEmpty())
time++;
}
return countFresh!=0?-1:time;
}
}
Complexity Analysis
- Time Complexity: O(n*m)
- Space Complexity: O(n*m)
Description You are given a m x n 2D grid initialized with these three possible values.
-1 : A wall or an obstacle.
0 : A gate.
INF - Infinity means an empty room. We use the value 2^31 - 1 = 2147483647 to represent INF as you may assume that the distance to a gate is less than 2147483647.
Fill each empty room with the distance to its nearest gate. If it is impossible to reach a Gate, that room should remain filled with INF
Example 1
Input:
[
[2147483647,-1,0,2147483647],
[2147483647,2147483647,2147483647,-1],
[2147483647,-1,2147483647,-1],
[0,-1,2147483647,2147483647]]
Output:
[
[3,-1,0,1],
[2,2,1,-1],
[1,-1,2,-1],
[0,-1,3,4]]
Explanation:
the 2D grid is:
INF -1 0 INF
INF INF INF -1
INF -1 INF -1
0 -1 INF INF
the answer is:
3 -1 0 1
2 2 1 -1
1 -1 2 -1
0 -1 3 4
Example 2
Input:
[
[0,-1],
[2147483647,2147483647]]
Output:
[
[0,-1],
[1,2]]
Tags
Company
Facebook
Google
Approach
- BFS or Topological Sort
- Start from the grid having 0 (add them to a queue)
- while queue is not empty:
- if neighbour of current position is INF, change it to 1+val coming from the queue and add it to queue
- otherwise take min of neighour's value and 1+val
Solution
public class Solution {
/**
* @param rooms: m x n 2D grid
* @return: nothing
*/
public void wallsAndGates(int[][] grid) {
int[][] dirs = {{-1, 0}, {1, 0}, {0, -1}, {0, 1} };
Queue<int[]> q = new LinkedList<>();
int n = grid.length, m = grid[0].length;
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++) {
if(grid[i][j] == 0)
q.offer(new int[]{i, j});
}
}
while (!q.isEmpty()) {
int size = q.size();
for (int i = 0; i < size; i++) {
int[] currPos = q.poll();
int currI = currPos[0], currJ = currPos[1];
int val = grid[currI][currJ];
for (int[] dir : dirs) {
if (currI + dir[0] < 0 || currJ + dir[1] < 0 || currI + dir[0] >= n || currJ + dir[1] >= m
|| grid[currI + dir[0]][currJ + dir[1]] == -1)
continue;
else if (grid[currI + dir[0]][currJ + dir[1]] == 2147483647) {
grid[currI + dir[0]][currJ + dir[1]] = 1 + val;
q.offer(new int[] { currI + dir[0], currJ + dir[1] });
} else {
grid[currI + dir[0]][currJ + dir[1]] = Math.min(grid[currI + dir[0]][currJ + dir[1]], 1 + val);
}
}
}
}
}
}
Complexity Analysis
- Time Complexity: O(k*n*m)
- Space Complexity: O(n*m)
There are a total of numCourses courses you have to take, labeled from 0 to numCourses - 1. You are given an array prerequisites where prerequisites[i] = [ai, bi] indicates that you
must take course bi first if you want to take course ai.
For example, the pair [0, 1], indicates that to take course 0 you have to first take course 1. Return true if you can finish all courses. Otherwise, return false.
Example 1:
Input: numCourses = 2, prerequisites = [[1,0]]
Output: true
Explanation: There are a total of 2 courses to take.
To take course 1 you should have finished course 0. So it is possible.
Example 2:
Constraints:
Approach
Topological Sort
- Have look a the solution for understanding the Topological sort algorithm
Solution
class Solution {
public boolean canFinish(int numCourses, int[][] prerequisites) {
// List<Integer> result = new ArrayList<>();
int result = 0;
// 4. For each source, add it to the result, subtract 1 from all of it's children's in-degree
// & add if any child has in-degree 0, add it to sources queue
while(!sources.isEmpty()) {
int vertex = sources.poll();
result++;
for(int child:graph.get(vertex)) {
inDegree.put(child, inDegree.get(child)-1);
if(inDegree.get(child) == 0)
sources.offer(child);
}
}
// 5. If size of result equal to numCourses then return true else return false
return result == numCourses;
}
}
Complexity Analysis
- Time Complexity: O(m*n)
- Space Complexity: O(m*n)
There are a total of numCourses courses you have to take, labeled from 0 to numCourses - 1. You are given an array prerequisites where prerequisites[i] = [ai, bi] indicates that you
must take course bi first if you want to take course ai.
For example, the pair [0, 1], indicates that to take course 0 you have to first take course 1. Return the ordering of courses you should take to finish all courses. If there are many valid
answers, return any of them. If it is impossible to finish all courses, return an empty array.
Example 1:
Example 2:
Example 3:
Constraints:
Aprroach
Ref: 8. Course Schedule (https://github.com/dipjul/NeetCode-150/blob/1db1597fe0d82d4741ecd5ee3600aea518824bb1/11.%20Graphs/8.CourseSchedule.md)
Topologicalo Sort
Solution
class Solution {
public int[] findOrder(int numCourses, int[][] prerequisites) {
List<Integer> result = new ArrayList<>();
// 4. For each source, add it to the result, subtract 1 from all of it's children's in-degree
// & add if any child has in-degree 0, add it to sources queue
while(!sources.isEmpty()) {
int vertex = sources.poll();
result.add(vertex);
for(int child:graph.get(vertex)) {
inDegree.put(child, inDegree.get(child)-1);
if(inDegree.get(child) == 0)
sources.offer(child);
}
}
if(result.size() != numCourses)
return new int[]{};
return result.stream().mapToInt(i->i).toArray();
}
}
Complexity Analysis
- Time Complexity: O(n*m)
- Space Complexity: O(n*m)
In this problem, a tree is an undirected graph that is connected and has no cycles.
You are given a graph that started as a tree with n nodes labeled from 1 to n, with one additional edge added. The added edge has two different vertices chosen from 1 to n, and was
not an edge that already existed. The graph is represented as an array edges of length n where edges[i] = [ai, bi] indicates that there is an edge between nodes ai and bi in the graph.
Return an edge that can be removed so that the resulting graph is a tree of n nodes. If there are multiple answers, return the answer that occurs last in the input.
Example 1:
Example 2:
Constraints:
n == edges.length
3 <= n <= 1000
edges[i].length == 2
1 <= ai < bi <= edges.length
ai != bi
There are no repeated edges.
The given graph is connected.
Approach
Ref: Union Find (https://github.com/dipjul/NeetCode-150/blob/e7002953ae531e571f4d148f591a265dda256d7d/Algorithms/1.UnionFind.md)
- Using UnionFind we'll check whether the nodes of the given edge are already connected without using the current edge
- if already connect which means this edge is reduntant
- else union the nodes of the current edge
Solution
class Solution {
int[] parent;
int[] rank;
public int[] findRedundantConnection(int[][] edges) {
int n = edges.length;
init(n);
int[] res = new int[2];
for(int[] edge:edges) {
if(!union(edge[0], edge[1]))
res = new int[]{ edge[0], edge[1] };
}
return res;
}
Complexity Analysis
- Time Complexity: O(n)
- Space Complexity: O(n)
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 to find the number of connected components in an undirected
graph.
Example 1:
0 3
| |
1 --- 2 4
Output: 2
Example 2:
Input: n = 5 and edges = [[0, 1], [1, 2], [2, 3], [3, 4]]
0 4
| |
1 --- 2 --- 3
Output: 1
Note: You can assume that no duplicate edges will appear in edges. Since all edges are undirected, [0, 1] is the same as [1, 0] and thus will not appear together in edges.
Approach
1. DFS
- Number of times dfs called is equal to the number of components
2. Union Find
- Take number of nodes as the number of components initially
- if the nodes of an edge are not already connected then decrease the count and union the nodes
Solution
// 1. DFS
class Solution {
public int countComponents(int n, int[][] edges) {
HashMap<Integer, List<Integer>> graph = new HashMap<Integer, List<Integer>>();
boolean[] visited = new boolean[n];
int count = 0;
// Step - 1 Build the graph
for(int i = 0; i < n; i++) {
graph.put(i, new ArrayList<Integer>());
}
UnionFind(int size) {
root = new int[size];
rank = new int[size];
if(rootX != rootY) {
if(rank[rootX] > rank[rootY])
root[rootY] = rootX;
else if(rank[rootX] < rank[rootY])
root[rootX] = rootY;
else {
root[rootY] = rootX;
rank[rootX]++;
}
}
}
Complexity Analysis
- Time Complexity:
- DFS: O(n)
- Union Find: O(n)
- Space Complexity:
- DFS: O(n+m)
- Union Find: O(n)
178 · Graph Valid Tree
(https://www.lintcode.com/problem/178/)
Medium
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 to check whether these edges make up a valid tree.
You can assume that no duplicate edges will appear in edges. Since all edges are undirected, [0, 1] is the same as [1, 0] and thus will not appear together in edges.
Example 1:
Input: n = 5 edges = [[0, 1], [0, 2], [0, 3], [1, 4]]
Output: true.
Example 2:
Input: n = 5 edges = [[0, 1], [1, 2], [2, 3], [1, 3], [1, 4]]
Output: false.
Approach
- check if number of edges is equal to n-1 or not
- if not equal return false;
- do dfs and put it in a set, size of set should be equal to number of nodes
Solution
public class Solution {
/**
* @param n: An integer
* @param edges: a list of undirected edges
* @return: true if it's a valid tree, or false
*/
public boolean validTree(int n, int[][] edges) {
// write your code here
if(edges.length != n-1)
return false;
if(n == 0 || n == 1)
return true;
Set<Integer> mark = new HashSet<>();
Map<Integer, List<Integer>> graph = new HashMap<>();
Complexity Analysis
- Time Complexity: O(n*m)
- Space Complexity: O(n+m)
A transformation sequence from word beginWord to word endWord using a dictionary wordList is a sequence of words beginWord -> s1 -> s2 -> ... -> sk such that:
Given two words, beginWord and endWord, and a dictionary wordList, return the number of words in the shortest transformation sequence from beginWord to endWord, or 0 if no
such sequence exists.
Example 1:
Input: beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log","cog"]
Output: 5
Explanation: One shortest transformation sequence is "hit" -> "hot" -> "dot" -> "dog" -> cog", which is 5 words long.
Example 2:
Constraints:
Approach
- Add the begin word to the wordList
- Create a graph such that neighbours of each node is differ by one character
- eg. fog would be neighbour of cog
- if endWord not present in the graph return 0
- How to find if two words are neighbour?
- Loop through the two words, whenever it differs increment the count
- if count == 1 return true else false
- Start bfs search from the beginWord untill we reach the endWord
- Keep count of distance from beginWord, return distance
Solution
class Solution {
if (!graph.containsKey(endWord)) return 0;
q.offer(beginWord);
if (q.size() == 0) return 0;
Set<String> visited = new HashSet<>();
int pathSize = 0;
while (!q.isEmpty()) {
int size = q.size();
pathSize++;
for (int i = 0; i < size; i++) {
String s1 = q.poll();
visited.add(s1);
if (s1.equals(endWord)) return pathSize;
for (String s : graph.get(s1)) {
if (!visited.contains(s)) q.offer(s);
}
}
}
return 0;
}
Complexity Analysis
- Time Complexity: O(n*n)
- Space Complexity: O(n+m)
Resources
1584. Min Cost to Connect All Points
(https://leetcode.com/problems/min-cost-to-
connect-all-points/)
Medium
You are given an array points representing integer coordinates of some points on a 2D-plane, where points[i] = [xi, yi].
The cost of connecting two points [xi, yi] and [xj, yj] is the manhattan distance between them: |xi - xj| + |yi - yj|, where |val| denotes the absolute value of val.
Return the minimum cost to make all points connected. All points are connected if there is exactly one simple path between any two points.
Example 1:
We can connect the points as shown above to get the minimum cost of 20.
Notice that there is a unique path between every pair of points.
Example 2:
Constraints:
1 <= points.length <= 1000 -106 <= xi, yi <= 106 All pairs (xi, yi) are distinct.
Approach
- MST
- PRIMS Algorithm
Solution
class Solution {
class Edge {
int[] x;
int[] y;
int cost;
Edge(int[] x, int[] y) {
this.x = x;
this.y = y;
this.cost = Math.abs(x[0]-y[0])+Math.abs(x[1]-y[1]);
}
}
// to detect cycle
private boolean detectCycle(int[] a, int[] b, Set<int[]> set) {
return set.contains(a) && set.contains(b);
}
}
Complexity Analysis
- Time Complexity: O(V*E)
- Space Complexity: O(V+E)
You are given a network of n nodes, labeled from 1 to n. You are also given times, a list of travel times as directed edges times[i] = (ui, vi, wi), where ui is the source node, vi is the
target node, and wi is the time it takes for a signal to travel from source to target.
We will send a signal from a given node k. Return the minimum time it takes for all the n nodes to receive the signal. If it is impossible for all the n nodes to receive the signal, return
-1.
Example 1:
Example 2:
Example 3:
Constraints:
Approach
Solution
public class Solution {
Complexity Analysis
- Time Complexity:
- Space Complexity:
There are n cities connected by some number of flights. You are given an array flights where flights[i] = [fromi, toi, pricei] indicates that there is a flight from city fromi to city toi with
cost pricei.
You are also given three integers src, dst, and k, return the cheapest price from src to dst with at most k stops. If there is no such route, return -1.
Example 1:
Input: n = 4, flights = [[0,1,100],[1,2,100],[2,0,100],[1,3,600],[2,3,200]], src = 0, dst = 3, k = 1
Output: 700
Explanation:
The graph is shown above.
The optimal path with at most 1 stop from city 0 to 3 is marked in red and has cost 100 + 600 = 700.
Note that the path through cities [0,1,2,3] is cheaper but is invalid because it uses 2 stops.
Example 2:
Example 3:
Constraints:
Approach
Ref: Bellman Ford (https://github.com/dipjul/NeetCode-
150/blob/9a8121cc3db395bc2b180b56c88524c678b72d03/Algorithms/4.Bellman-ford.md)
Solution
class Solution {
public int findCheapestPrice(int n, int[][] flights, int src, int dst, int k) {
int[] cost = new int[n];
Arrays.fill(cost, Integer.MAX_VALUE);
int[] tmp = new int[n];
Arrays.fill(tmp, Integer.MAX_VALUE);
cost[src] = 0;
tmp[src] = 0;
while(k >= 0) {
for(int[] flight : flights) {
if(cost[flight[0]] != Integer.MAX_VALUE) {
int newCost = cost[flight[0]]+flight[2];
if(newCost < tmp[flight[1]])
tmp[flight[1]] = newCost;
}
}
cost = Arrays.copyOfRange(tmp, 0, n);
k--;
}
return cost[dst] == Integer.MAX_VALUE?-1:cost[dst];
}
}
Complexity Analysis
- Time Complexity: O(k*E), E size of flights array
- Space Complexity: O(n)
Resources
70. Climbing Stairs
(https://leetcode.com/problems/climbing-
stairs/)
Easy
Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top?
Example 1:
Input: n = 2
Output: 2
Explanation: There are two ways to climb to the top.
1. 1 step + 1 step
2. 2 steps
Example 2:
Input: n = 3
Output: 3
Explanation: There are three ways to climb to the top.
1. 1 step + 1 step + 1 step
2. 1 step + 2 steps
3. 2 steps + 1 step
Constraints:
1 <= n <= 45
Approach
- Problem effectively becomes fibonacci
Solution
class Solution {
public int climbStairs(int n) {
int one = 1, two = 1;
for(int i = 2; i <= n; i++) {
int tmp = one;
one = one + two;
two = tmp;
}
return one;
}
}
Complexity Analysis
- Time Complexity: O(N)
- Space Complexity: O(1)
You are given an integer array cost where cost[i] is the cost of ith step on a staircase. Once you pay the cost, you can either climb one or two steps.
You can either start from the step with index 0, or the step with index 1.
Example 1:
Example 2:
Input: cost = [1,100,1,1,1,100,1,1,100,1]
Output: 6
Explanation: You will start at index 0.
- Pay 1 and climb two steps to reach index 2.
- Pay 1 and climb two steps to reach index 4.
- Pay 1 and climb two steps to reach index 6.
- Pay 1 and climb one step to reach index 7.
- Pay 1 and climb two steps to reach index 9.
- Pay 1 and climb one step to reach the top.
The total cost is 6.
Constraints:
Approach
- Start from the end of the array
- Recursive formula:
- cost[i] = cost[i] + min(cost[i+1], cost[i+2])
- return min(cost[o], cost[1])
Solution
class Solution {
public int minCostClimbingStairs(int[] cost) {
Complexity Analysis
- Time Complexity: O(N)
- Space Complexity O(1)
You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed, the only constraint stopping you from robbing each of them
is that adjacent houses have security systems connected and it will automatically contact the police if two adjacent houses were broken into on the same night.
Given an integer array nums representing the amount of money of each house, return the maximum amount of money you can rob tonight without alerting the police.
Example 1:
Input: nums = [1,2,3,1]
Output: 4
Explanation: Rob house 1 (money = 1) and then rob house 3 (money = 3).
Total amount you can rob = 1 + 3 = 4.
Example 2:
Constraints:
Approach
Pattern:
for loop
dp[i] = max(dp[i-1], nums[i]+dp[i-2]);
- either take the amount till previous element or else add current element to the amount till pre previous elements
Solution
class Solution {
public int rob(int[] nums) {
int n = nums.length;
if(n == 1)
return nums[0];
int[] dp = new int[n];
dp[0] = nums[0];
dp[1] = Math.max(nums[0], nums[1]);
for(int i = 2; i < n; i++) {
dp[i] = Math.max(dp[i-1], nums[i]+dp[i-2]);
}
return dp[n-1];
}
// optimized
class Solution {
public int rob(int[] nums) {
int n = nums.length;
if(n == 1)
return nums[0];
int prev2 = nums[0];
int prev1 = Math.max(nums[0], nums[1]);
You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed. All houses at this place are arranged in a circle. That
means the first house is the neighbor of the last one. Meanwhile, adjacent houses have a security system connected, and it will automatically contact the police if two adjacent houses
were broken into on the same night.
Given an integer array nums representing the amount of money of each house, return the maximum amount of money you can rob tonight without alerting the police.
Example 1:
Example 2:
Example 3:
Constraints:
Approach
Reference: 3. House Robber (https://github.com/dipjul/NeetCode-150/blob/d95d91ca2c7e0e25f421e3959ce0c0b62d9ba5a0/13.%201-
D%20Dynamic%20Programming/3.HouseRobber.md)
- Reuse house robber, 1st time for [0, n-1] & 2nd time for [1, n]
- Return max out of them
Solution
class Solution {
public int rob(int[] nums) {
int n = nums.length;
if(n == 1)
return nums[0];
if(n == 2)
return Math.max(nums[0], nums[1]);
int prev2 = nums[0];
int prev1 = Math.max(nums[0], nums[1]);
Complexity Analysis
- Time Complexity: O(2 * N) ~ O(N)
- Space Complexity: O(1)
Example 1:
Input: s = "babad"
Output: "bab"
Explanation: "aba" is also a valid answer.
Example 2:
Input: s = "cbbd"
Output: "bb"
Constraints:
Approach
Approach 1:
- for each index, try to find odd length & even length palindromes
- odd: start the inner loop from the same index
- even: start the inner loop one pointer on i and other at i+1
- expand towards the left and right of i while the chars are same
- keep checking the len, and store the start and end
- substring(start,end+1), end+1 because the substring method takes end index one more than the original end index
Approach 2:
- Manacher Algorithm
Solution
class Solution {
public String longestPalindrome(String s) {
int resLen = 0, start = 0, end = 0;
class Solution {
public String longestPalindrome(String s) {
StringBuilder sb = new StringBuilder();
// appending chars before, inbetween and end to make the string
// such that we can use the manacher odd algorithm
sb.append("$");
for(int i = 0; i < s.length(); i++) {
sb.append("#");
sb.append(s.charAt(i));
}
sb.append("#");
sb.append("&");
int[] p = manacher_odd(sb.toString());
int center = 0, resLen = 0;
for(int i = 0; i < p.length; i++) {
if(p[i] > resLen) {
center = i;
resLen = p[i];
}
}
Complexity Analysis
- Time Complexity:
- Approach 1: O(N*N)
- Approach 2: O(N)
- Space Complexity:
- Approach 1: O(1)
- Approach 2: O(N)
Example 1:
Input: s = "abc"
Output: 3
Explanation: Three palindromic strings: "a", "b", "c".
Example 2:
Input: s = "aaa"
Output: 6
Explanation: Six palindromic strings: "a", "a", "a", "aa", "aa", "aaa".
Constraints:
Approach
Reference: 5.LongestPalindromicSubstring (https://github.com/dipjul/NeetCode-150/blob/7961198c07e09a081fec9fbcc445e315bab042a7/13.%201-
D%20Dynamic%20Programming/5.LongestPalindromicSubstring.md)
Approach 1:
- expand around every element as a center
- ood length (i,i)
- even length (i,i+1)
- increment for each match
Approach 2:
- Manacher Algorithm
- every element in p[i]
- (p[i]+1)/2
Solution
class Solution {
public int countSubStrings(String s) {
if (s.length() < 2) {
return s.length();
}
int result = 0;
for (int i = 0; i < s.length(); i++) {
// Odd Length
int left = i, right = i;
while (left >=0 && right < s.length() && s.charAt(left) == s.charAt(right)) {
result++;
left -=1;
right +=1;
}
// Even Length
left = i;
right = i + 1;
while (left >=0 && right < s.length() && s.charAt(left) == s.charAt(right)) {
result++;
left -=1;
right +=1;
}
}
return result;
}
}
class Solution {
public int countSubstrings(String s) {
StringBuilder sb = new StringBuilder();
sb.append("$");
for(int i = 0; i < s.length(); i++) {
sb.append("#");
sb.append(s.charAt(i));
}
sb.append("#");
sb.append("@");
int[] p = manacher_odd(sb.toString());
int ans = 0;
for(int i = 0; i < p.length; i++)
ans += (p[i]+1)/2;
return ans;
}
while(s.charAt(i-(p[i]+1)) == s.charAt(i+(p[i]+1)))
p[i]++;
return p;
}
}
Complexity Analysis
- Time Complexity:
- Approach 1: O(N*N)
- Approach 2: O(N)
- Space Complexity:
- Approach 1: O(1)
- Approach 2: O(N)
A message containing letters from A-Z can be encoded into numbers using the following mapping:
...
To decode an encoded message, all the digits must be grouped then mapped back into letters using the reverse of the mapping above (there may be multiple ways). For example,
"11106" can be mapped into:
Note that the grouping (1 11 06) is invalid because "06" cannot be mapped into 'F' since "6" is different from "06".
Given a string s containing only digits, return the number of ways to decode it.
The test cases are generated so that the answer fits in a 32-bit integer.
Example 1:
Input: s = "12"
Output: 2
Explanation: "12" could be decoded as "AB" (1 2) or "L" (12).
Example 2:
Input: s = "226"
Output: 3
Explanation: "226" could be decoded as "BZ" (2 26), "VF" (22 6), or "BBF" (2 2 6).
Example 3:
Input: s = "06"
Output: 0
Explanation: "06" cannot be mapped to "F" because of the leading zero ("6" is different from "06").
Constraints:
Approach
- Approach
- take an dp array of size 1 greater than len(s)
- at the last index we'll keep 1
- for every char, if char not equal of 0
- dp[i] += dp[i+1]
- if s(i,i+2) is < 26
- dp[i] += dp[i+2]
- at last we'll have the ans at dp[0]
- Optimize
- pattern seems like fibonacci
- we can replace the array with three variables
- curr will have dp[i]
- prev will have dp[i+1]
- prev2 will have dp[i+2]
Solution
class Solution {
Complexity Analysis
- Time Complexity:
- Approach 1 & Approach 2: O(N)
- Space Complexity:
- Approach 1: O(N), dp array of n size
- Approach 2: O(1), 3 variables
You are given an integer array coins representing coins of different denominations and an integer amount representing a total amount of money.
Return the fewest number of coins that you need to make up that amount. If that amount of money cannot be made up by any combination of the coins, return -1.
You may assume that you have an infinite number of each kind of coin.
Example 1:
Input: coins = [1,2,5], amount = 11
Output: 3
Explanation: 11 = 5 + 5 + 1
Example 2:
Example 3:
Constraints:
Approach
- we'll have dp array of size amount+1
- we'll initiaze the array with large value
- dp[0] would be 0
- for in range(1, amount)
- for each coin
- dp[i] = min(dp[i], 1 + dp[i-coin])
- dp[amount] will either have the ans or else it'll have the default value
Solution
class Solution {
public int coinChange(int[] coins, int amount) {
int[] dp = new int[amount + 1];
Arrays.fill(dp, amount + 1);
dp[0] = 0;
for (int i = 1; i <= amount; i++) {
for (int j = 0; j < coins.length; j++) {
if (coins[j] <= i) {
dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1);
}
}
}
return dp[amount] > amount ? -1 : dp[amount];
}
}
Complexity Analysis
- Time Complex: O(N*K), N: amount+1, K = coins.length
- Space complexity: O(N), N: amount+1
Given an integer array nums, find a contiguous non-empty subarray within the array that has the largest product, and return the product.
The test cases are generated so that the answer will fit in a 32-bit integer.
Example 1:
Example 2:
Constraints:
Approach
- two variable to keep max & min at that index
- result, initially stores the max element present in the array
- if we encounter 0, min and max set to 1
- else
- min = min(min*arr[i],max*arr[i],arr[i])
- max = max(prevMin*arr[i], max*arr[i], arr[i])
- result = max(max, result)
Solution
class Solution {
public int maxProduct(int[] nums) {
int n = nums.length;
int min = nums[0], max = nums[0];
int result = nums[0];
return result;
}
}
Complexity Analysis
- Time Complexity: O(N)
- Space Complexity: O(1)
Given a string s and a dictionary of strings wordDict, return true if s can be segmented into a space-separated sequence of one or more dictionary words.
Note that the same word in the dictionary may be reused multiple times in the segmentation.
Example 1:
Example 2:
Example 3:
Constraints:
Approach
Decision tree of Backtracking
Cache
Bottom up
Solution
class Solution {
public boolean wordBreak(String s, List<String> wordDict) {
int n = s.length();
boolean dp[] = new boolean[n+1];
dp[n] = true;
if(dp[i])
break;
}
}
return dp[0];
}
}
Complexity Analysis
- Time Complexity: O(N*len(wordInDict))
- Space Complexity: O(N)
Given an integer array nums, return the length of the longest strictly increasing subsequence.
A subsequence is a sequence that can be derived from an array by deleting some or no elements without changing the order of the remaining elements. For example, [3,6,2,7] is a
subsequence of the array [0,3,1,6,2,2,7].
Example 1:
Example 2:
Example 3:
Constraints:
Approach
- Starting from 2nd last element, lis[] will store 1 for all the elements
- compare it with the next element, if the next element is less than current element
- add max of lis[curr], 1+lis[next]
Solution
class Solution {
public int lengthOfLIS(int[] nums) {
int n = nums.length;
int[] lis = new int[n];
Arrays.fill(lis, 1);
lis[n-1] = 1;
int res = 1;
for(int i = n-2; i >= 0; i--) {
for(int j = i+1; j < n; j++) {
if(nums[i] < nums[j])
lis[i] = Math.max(lis[i], 1+lis[j]);
}
res = Math.max(res, lis[i]);
}
return res;
}
}
Complexity Analysis
- Time Complexity: O(n^2)
- Space Complexity: O(n)
Given a non-empty array nums containing only positive integers, find if the array can be partitioned into two subsets such that the sum of elements in both subsets is equal.
Example 1:
Example 2:
Approach
- sum of all the elements, if it's odd return false
- otherwise, find whther there is a subset such that it's equal to sum/2
Solution
class Solution {
Boolean[][] dp;
public boolean canPartition(int[] nums) {
int sum = 0;
for(int num : nums) {
sum += num;
}
if(sum%2 != 0)
return false;
dp = new Boolean[nums.length][sum/2+1];
return subsetSum(nums, 0, sum/2);
}
// DP
private boolean subsetSum(int[] nums, int ind, int sum) {
if(ind >= nums.length || sum < 0)
return false;
if(sum == 0)
return true;
if(dp[ind][sum] != null)
return dp[ind][sum];
dp[ind][sum] = subsetSum(nums, ind+1, sum-nums[ind]) || subsetSum(nums, ind+1, sum);
return dp[ind][sum];
}
// Recursion
private boolean subsetSum2(int[] nums, int ind, int sum) {
if(ind >= nums.length)
return false;
if(sum == 0)
return true;
return subsetSum(nums, ind+1, sum-nums[ind]) || subsetSum(nums, ind+1, sum);
}
}
Complexity Analysis
- Time Complexity: O(N*Sum)
- Space Complexity: O(N*Sum)
Resources
62. Unique Paths
(https://leetcode.com/problems/unique-
paths/)
Medium
There is a robot on an m x n grid. The robot is initially located at the top-left corner (i.e., grid[0][0]). The robot tries to move to the bottom-right corner (i.e., grid[m - 1][n - 1]). The robot
can only move either down or right at any point in time.
Given the two integers m and n, return the number of possible unique paths that the robot can take to reach the bottom-right corner.
The test cases are generated so that the answer will be less than or equal to 2 * 109.
Example 1:
Input: m = 3, n = 7
Output: 28
Example 2:
Input: m = 3, n = 2
Output: 3
Explanation: From the top-left corner, there are a total of 3 ways to reach the bottom-right corner:
1. Right -> Down -> Down
2. Down -> Down -> Right
3. Down -> Right -> Down
Constraints:
Approach
- Last row and last column would have only one way
- others:
- dp[i][j] = dp[i+1][j]+dp[i][j+1];
- dp[0][0] would have the result
Solution
class Solution {
public int uniquePaths(int m, int n) {
int[][] dp = new int[m][n];
// last column
for(int i = 0; i < m; i++) {
dp[i][n-1] = 1;
}
// last row
for(int i = 0; i < n; i++) {
dp[m-1][i] = 1;
}
Complexity Analysis
- Time Complexity: O(m*n)
- Space Complexity: O(m*n)
Given two strings text1 and text2, return the length of their longest common subsequence. If there is no common subsequence, return 0.
A subsequence of a string is a new string generated from the original string with some characters (can be none) deleted without changing the relative order of the remaining
characters.
For example, "ace" is a subsequence of "abcde". A common subsequence of two strings is a subsequence that is common to both strings.
Example 1:
Example 2:
Example 3:
Constraints:
Approach
- Classic DP problem
- create a table, chars of one string as row and other as column
- fill out the value
- Formula that would appear
- if chars are equal: dp[i][j] = 1 + dp[i-1][j-1], (diagonally prev element)
- else: dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]), max(top element, left element)
Solution
class Solution {
public int longestCommonSubsequence(String text1, String text2) {
int n1 = text1.length(), n2 = text2.length();
int[][] dp = new int[n1+1][n2+1];
Complexity Analysis
- Time Compolexity: O(N*M), N : length of string 1, M : length of string 2
- Space Complexity: O(N*M)
You are given an array prices where prices[i] is the price of a given stock on the ith day.
Find the maximum profit you can achieve. You may complete as many transactions as you like (i.e., buy one and sell one share of the stock multiple times) with the following
restrictions:
After you sell your stock, you cannot buy stock on the next day (i.e., cooldown one day). Note: You may not engage in multiple transactions simultaneously (i.e., you must sell the
stock before you buy again).
Example 1:
Example 2:
Constraints:
Solution
class Solution {
public int maxProfit(int[] prices) {
boolean buy = false;
Map<String, Integer> mp = new HashMap<>();
return helper(prices, 0, mp, true);
}
private int helper(int[] prices, int index, Map<String, Integer> mp, boolean buying) {
if(index >= prices.length)
return 0;
if(mp.containsKey("("+index+","+buying+")"))
return mp.get("("+index+","+buying +")");
// in both the cases we have the cooldown
int cooldown = helper(prices, index+1, mp, buying);
if(buying) {
int buy = helper(prices, index+1, mp, !buying) - prices[index];
mp.put("("+index+","+buying +")", Math.max(cooldown, buy));
} else {
// we can't buy in next index so we pass the index+2
int sell = helper(prices, index+2, mp, !buying) + prices[index];
mp.put("("+index+","+buying +")", Math.max(cooldown, sell));
}
return mp.get("("+index+","+buying +")");
}
}
Complexity Analysis
- Time Complexity: O(N)
- Space Complexity: O(N)
You are given an integer array coins representing coins of different denominations and an integer amount representing a total amount of money.
Return the number of combinations that make up that amount. If that amount of money cannot be made up by any combination of the coins, return 0.
You may assume that you have an infinite number of each kind of coin.
Example 1:
Example 2:
Example 3:
Constraints:
Approach
- Make a table and go through a example
- generic recursive formula:
- dp[i][j] = dp[i-1][j] + dp[i][j-coin]
- take care of edge cases
Solution
class Solution {
public int change(int amount, int[] coins) {
int n = coins.length;
int dp[][] = new int[n][amount+1];
return dp[n-1][amount];
}
// Consise
public int change(int amount, int[] coins) {
int[][] dp = new int[coins.length+1][amount+1];
dp[0][0] = 1;
// Optimal
public int change(int amount, int[] coins) {
int[] dp = new int[amount + 1];
dp[0] = 1;
for (int coin : coins) {
for (int i = coin; i <= amount; i++) {
dp[i] += dp[i-coin];
}
}
return dp[amount];
}
}
Complexity Analysis
- Time Complexity: O(Amount*No. of coins)
- Space Complexity:
- 2D: O(Amount*No. of coins)
- Optimal: O(Amount+1)
329. Longest Increasing Path in a Matrix
(https://leetcode.com/problems/longest-
increasing-path-in-a-matrix/)
Hard
Given an m x n integers matrix, return the length of the longest increasing path in matrix.
From each cell, you can either move in four directions: left, right, up, or down. You may not move diagonally or move outside the boundary (i.e., wrap-around is not allowed).
Example 1:
Example 2:
Example 3:
Constraints:
m == matrix.length
n == matrix[i].length
1 <= m, n <= 200
Approach
- DFS/backtracking with DP
- Start from each element in the matrix
- Find the longest increasing path we can make from that position
- by moving towards the 4 directions
- Store the result in a table
- Reuse the value
Solution
class Solution {
private int backtrack(int[][] matrix, int i, int j, int prev, int[][] cache) {
if(i < 0 || j < 0 || i >= matrix.length || j >= matrix[0].length || prev >= matrix[i][j])
return 0;
if(cache[i][j] != 0)
return cache[i][j];
int max = 1;
cache[i][j] = max;
return max;
}
}
Complexity Analysis
- Time Complexity: dfs: O(n*m), we'll go through each position, after that it'll return from any position in O(1)
- Space Complexity: O(n*m)
Share Given two strings word1 and word2, return the minimum number of operations required to convert word1 to word2.
Insert a character
Delete a character
Replace a character
Example 1:
Constraints:
Aproach
- make a table with one word as row and other as column,
- append same char at the start of the both words to represent that both are empty string then 0 operation rqd to convert from word
- generic recursive equation:
- dp[i][j] = dp[i-1][j-1], if char are same
- dp[i][j] = 1 + min(dp[i-1][j], dp[i-1][j-1], dp[i][j-1]), i.e. 1 + min(left, top, diagonally prev)
- take care of base cases
Solution
class Solution {
public int minDistance(String word1, String word2) {
int m = word1.length(), n = word2.length();
int dp[][] = new int[n+1][m+1];
for(int i = 1; i <= n; i++) {
dp[i][0] = i;
}
if(ch1 == ch2)
dp[i][j] = dp[i-1][j-1];
else
dp[i][j] = 1 + Math.min(dp[i-1][j], Math.min(dp[i-1][j-1], dp[i][j-1]));
}
}
return dp[n][m];
}
}
Complexity Analysis
- Time Complexity: O(len(word1)*len(word2))
- Space Complexity: O(len(word1)*len(word2))
Resources
53. Maximum Subarray
Easy
Given an integer array nums, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum.
Example 1:
Example 2:
Example 3:
Constraints:
Follow up: If you have figured out the O(n) solution, try coding another solution using the
divide and conquer approach, which is more subtle.
class Solution {
public int maxSubArray(int[] nums) {
int n = nums.length;
int total = 0;
int result = nums[0];
return result;
}
}
Return true if you can reach the last index, or false otherwise.
Example 1:
Example 2:
Constraints:
Aprroach
- one variable(for eg. ans) is keeping upto which index can we move from the current index
- if ans value is less than the current index, which means we can't move to the current index
- at every index we check if you can better the ans,
which means if we can move to a higher index than the current index stored in ans
- if ans is sotring the value more than equal to the length of the given array
Solution
class Solution {
public boolean canJump(int[] nums) {
int ans = 0, n = nums.length;
for(int i = 0; i < n-1; i++) {
if(ans < i)
return false;
if(ans < i+nums[i])
ans = i+nums[i];
if(ans >= n-1)
return true;
}
return ans >= n-1;
}
}
Complexity Analysis
- Time Complexity: O(N)
- Space Complexity: O(1)
Given an array of non-negative integers nums, you are initially positioned at the first index of the array.
Each element in the array represents your maximum jump length at that position.
Your goal is to reach the last index in the minimum number of jumps.
You can assume that you can always reach the last index.
Example 1:
Example 2:
Constraints:
Approach
- dp array initialized to large value, later on it will store the min jumps required to reach last index from each index
- we start from end, second last index, try to see if we can move to the last index
- for each index you look for the min step we need to reach last index
- Pattern:
- for each nums's index(i):
- for range(0,num) (j):
- dp[i] = min(dp[i], 1 + dp[i+j]
TODO : Optimization
Solution
class Solution {
public int jump(int[] nums) {
int n = nums.length;
int dp[] = new int[n];
Arrays.fill(dp, 10000);
dp[n - 1] = 0;
Complexity Analysis
- Time Complexity: O(k*N)
- Space Complexity: O(N)
There are n gas stations along a circular route, where the amount of gas at the ith station is gas[i].
You have a car with an unlimited gas tank and it costs cost[i] of gas to travel from the ith station to its next (i + 1)th station. You begin the journey with an empty tank at one of the gas
stations.
Given two integer arrays gas and cost, return the starting gas station's index if you can travel around the circuit once in the clockwise direction, otherwise return -1. If there exists a
solution, it is guaranteed to be unique
Example 1:
Example 2:
Constraints:
n == gas.length == cost.length
1 <= n <= 105
Approach
- Trivial:
- we'll store the difference of gas[i]-cost[i]
- for all the +ve differences we do the process
TODO:Optimization
Solution
class Solution {
public int canCompleteCircuit(int[] gas, int[] cost) {
int ind = 0, sum = 0;
int[] diff = new int[gas.length];
PriorityQueue<Pair> pq = new PriorityQueue<>((a,b)->b.value-a.value);
for (int i = 0; i < gas.length; i++) {
diff[i] = gas[i] - cost[i];
sum += diff[i];
if(diff[i]>=0)
pq.offer(new Pair(diff[i], i));
}
if (sum < 0)
return -1;
while(!pq.isEmpty()) {
Pair p = pq.poll();
if (p.value >= 0) {
int pathSum = 0;
ind = p.index;
int j = p.index;
do {
pathSum += diff[j];
if (pathSum < 0)
break;
j = (j + 1) % gas.length;
} while(j != p.index);
if (pathSum >= 0)
break;
}
}
return ind;
}
}
class Pair {
int value;
int index;
Pair(int v, int i) {
value = v;
index = i;
}
}
Complexity Analysis
- Time Complexity: O(k*N), k is number of elements in diff array that are 0 or +ve
- Space Complexity: O(N)
Alice has some number of cards and she wants to rearrange the cards into groups so that each group is of size groupSize, and consists of groupSize consecutive cards.
Given an integer array hand where hand[i] is the value written on the ith card and an integer groupSize, return true if she can rearrange the cards, or false otherwise.
Example 1:
Example 2:
Constraints:
Approach
// TODO
Solution
class Solution {
public boolean isNStraightHand(int[] hand, int groupSize) {
if(hand.length % groupSize != 0)
return false;
while(!pq.isEmpty()) {
int min = pq.peek();
int sz = 0;
while(sz < groupSize) {
if(!mp.containsKey(min))
return false;
mp.put(min, mp.get(min)-1);
if(mp.get(min) == 0) {
mp.remove(min);
int val = pq.poll();
if(val != min)
return false;
}
min++;
sz++;
}
}
return true;
}
}
Complexity Analysis
- Time Complexity:
- Space Complexity:
Given a string s containing only three types of characters: '(', ')' and '*', return true if s is valid.
Any left parenthesis '(' must have a corresponding right parenthesis ')'. Any right parenthesis ')' must have a corresponding left parenthesis '('. Left parenthesis '(' must go before the
corresponding right parenthesis ')'. '*' could be treated as a single right parenthesis ')' or a single left parenthesis '(' or an empty string "".
Example 1:
Input: s = "()"
Output: true
Example 2:
Input: s = "(*)"
Output: true
Example 3:
Input: s = "(*))"
Output: true
Constraints:
Approach
Approach 1:
- backtrack
- count+1 if '('
- count-1 if ')'
- For '*':
- 3 calls: count+1, count-1, count+0
- dp (index, count) = true/false
Approach 2: greedy
Solution
class Solution {
Boolean[][] dp;
Complexity Analysis
- Time Complexity:
- Approach 1: O(n^3)
- Approach 2: O(n)
- Space Complexity:
- Approach 1: O(n)
- Approach 2: O(1)
Resources
57. Insert Interval
(https://leetcode.com/problems/insert-
interval/)
Medium
You are given an array of non-overlapping intervals intervals where intervals[i] = [starti, endi] represent the start and the end of the ith interval and intervals is sorted in ascending
order by starti. You are also given an interval newInterval = [start, end] that represents the start and end of another interval.
Insert newInterval into intervals such that intervals is still sorted in ascending order by starti and intervals still does not have any overlapping intervals (merge overlapping intervals if
necessary).
Example 1:
Constraints:
Approach
- Step 1: while interval's end is lesser than new interval's start, keep adding it to result
- After step 1, we'll be at the position where new interval will start(either overlap or as the initial interval or as the last inter
- Step 2: while intervals's start is <= new interval's end
- Keep taking the min start & max end and assign into the new interval(overlapping)
- After step 2, we'll have the merged new interval, add it to result
- Step 3: while intervals not finished processing
- keep adding them to the result
Solution
class Solution {
Complexity Analysis
- Time Complexity: O(n)
- Space Complexity: O(n)
Given an array of intervals where intervals[i] = [starti, endi], merge all overlapping intervals, and return an array of the non-overlapping intervals that cover all the intervals in the input.
Example 1:
Example 2:
Constraints:
Approach
- Sort the intervals by start time
- Use arr to store the merged list
- Start by inserting the first element
- looping through all the other intervals
- check if last interval inserted into arr overlapped with current interval
- if yes then create a new interval and push to arr
- else insert the current interval to arr
Solution
class Solution {
public int[][] merge(int[][] intervals) {
Arrays.sort(intervals, (a, b) -> a[0] - b[0]);
List<int[]> arr = new ArrayList<>();
arr.add(intervals[0]);
int start = intervals[0][0];
int end = intervals[0][1];
for (int i = 1; i < intervals.length; i++) {
int[] curr = intervals[i];
int[] prev = arr.get(arr.size() - 1);
if (curr[0] <= prev[1]) {
arr.remove(arr.size() - 1);
start = Math.min(curr[0], prev[0]);
end = Math.max(curr[1], prev[1]);
arr.add(new int[]{start, end});
} else {
arr.add(curr);
}
}
return arr.toArray(new int[arr.size()][]);
}
}
Complexity Analysis
- Time Complexity: O(nlogn)
- Space Complexity: O(n), for arr
Given an array of intervals intervals where intervals[i] = [starti, endi], return the minimum number of intervals you need to remove to make the rest of the intervals non-overlapping.
Example 1:
Example 2:
Example 3:
Constraints:
Approach
- Sort the intervals by end time
- store the first interval (we're storing it as prev)
- loop through the intervals starting the 2nd interval
- if current interval overlap with prev the increment the count
- else assign the current interval to the prev
Solution
class Solution {
public int eraseOverlapIntervals(int[][] intervals) {
if(intervals.length <= 1)
return 0;
Arrays.sort(intervals, (a,b)->a[1]-b[1]);
int count = 0;
int[] prev = intervals[0];
for(int i = 1; i < intervals.length; i++) {
int[] curr = intervals[i];
if(prev[1] > curr[0])
count++;
else
prev = intervals[i];
}
return count;
}
}
Complexity Analysis
- Time Complexity: O(nlogn)
- Space Complexity: O(1)
Description Given an array of meeting time intervals consisting of start and end times [[s1,e1],[s2,e2],...] (si < ei), determine if a person could attend all meetings.
Wechat reply the【Video】get the free video lessons , the latest frequent Interview questions , etc. (wechat id :jiuzhang15)
Example 1
Example 2
if(intervals.size() == 0 || intervals.size() == 1)
return true;
Collections.sort(intervals, (a,b)->a.end-b.end);
Interval next = intervals.get(intervals.size()-1);
for(int i = intervals.size()-2; i >= 0; i--) {
Interval current = intervals.get(i);
Given an array of meeting time intervals consisting of start and end times [[s1,e1],[s2,e2],...] (si < ei), find the minimum number of conference rooms required.)
Example 1
Example2
Approach
Approach 1:
- Create a array of size, largest element - smallest element + 1
- for each interval:
- increment all the index between [start, end)
- keep tracking the max element in that array, that's the answer
Approach 2(Better):
- Sort starting time and ending seperatedly
- Two pointers one from traversing through the start[] and the other through the end[]
- keep track of max count(it would have the answer)
- if pointer pointing at start < pointer pointing at end
- increment the count & move the start pointer forward
- else
- decrement the count & move the end pointer forward
Solution
/**
* Definition of Interval:
* public class Interval {
* int start, end;
* Interval(int start, int end) {
* this.start = start;
* this.end = end;
* }
* }
*/
return usedRooms;
}
}
Complexity Analysis
- Time Complexity:
- Better approach: O(nlogn)
- Space Complexity:
- Better approach: O(n)
Resources
48. Rotate Image
Medium
You are given an n x n 2D matrix representing an image, rotate the image by 90 degrees (clockwise).
You have to rotate the image in-place, which means you have to modify the input 2D matrix directly. DO NOT allocate another 2D matrix and do the rotation.
Example 1:
Example 2:
Constraints:
n == matrix.length == matrix[i].length
1 <= n <= 20
-1000 <= matrix[i][j] <= 1000
Approach
- Roatate = Transpose + Reverse
Solution
class Solution {
public void rotate(int[][] matrix) {
transpose(matrix);
for(int[] nums : matrix) {
reverse(nums);
}
}
Complexity Analysis
- Time Complexity: O(n), n : number of elements in the matrix
- Space Complexity: O(1)
54. Spiral Matrix
Medium
Example 1:
Example 2:
Constraints:
m == matrix.length
n == matrix[i].length
1 <= m, n <= 10
-100 <= matrix[i][j] <= 100
Approach
Solution
class Solution {
public List<Integer> spiralOrder(int[][] matrix) {
List<Integer> res = new ArrayList<>();
int m = matrix.length - 1;
int n = matrix[0].length - 1;
int sr = 0, sc = 0;
int i = sr, j = sc;
while (sc <= n || sr <= m) {
// 1st row
while (j <= n) {
res.add(matrix[i][j]);
j++;
}
sr++;
j = n;
i = sr;
// condition
if (i > m || j > n) {
break;
}
// last colunm
while (i <= m) {
res.add(matrix[i][j]);
i++;
}
n--;
i = m;
j = n;
if (i > m || j > n) {
break;
}
// last row
while (j >= sc) {
res.add(matrix[i][j]);
j--;
}
m--;
j = sc;
i = m;
if (i > m || j > n) {
break;
}
// 1st column
while (i >= sr) {
res.add(matrix[i][j]);
i--;
}
sc++;
i = sr;
j = sc;
if (i > m || j > n) {
break;
}
}
return res;
}
}
Complexity Analysis
- Time Complexity: O(n), n : number of elements in the matrix
- Space Complexity: O(1)
Given an m x n integer matrix matrix, if an element is 0, set its entire row and column to 0's.
Example 1:
Example 2:
Constraints:
m == matrix.length
n == matrix[0].length
1 <= m, n <= 200
-231 <= matrix[i][j] <= 231 - 1
Follow up:
Approach
- Use the first row and column to keep track of zeroes
- Use one variable for the 0th row or 0 column depending upon our choice
Solution
class Solution {
public void setZeroes(int[][] matrix) {
int col0 = 1;
int n = matrix.length, m = matrix[0].length;
// first column
for(int i = 0; i < n; i++) {
if(matrix[i][0] == 0)
col0 = 0;
}
// first row
for(int i = 0; i < m; i++) {
if(matrix[0][i] == 0)
matrix[0][0] = 0;
}
// starting from (1,1)
for(int i = 1; i < n; i++) {
for(int j = 1; j < m; j++) {
if(matrix[i][j] == 0) {
matrix[i][0] = 0;
matrix[0][j] = 0;
}
}
}
if(matrix[0][0] == 0) {
for(int i = 1; i < m; i++)
matrix[0][i] = 0;
}
if(col0 == 0) {
for(int i = 0; i < n; i++)
matrix[i][0] = 0;
}
}
}
Complexity Analysis
- Time Complexity: O(N), N : numbero of elements in the matrix
- Space Complexity: O(1)
Starting with any positive integer, replace the number by the sum of the squares of its digits.
Repeat the process until the number equals 1 (where it will stay), or it loops endlessly in a cycle which does not include 1.
Those numbers for which this process ends in 1 are happy.
Input: n = 19
Output: true
Explanation:
12 + 92 = 82
82 + 22 = 68
62 + 82 = 100
12 + 02 + 02 = 1
Example 2:
Input: n = 2
Output: false
Constraints:
class Solution {
public boolean isHappy(int n) {
int slow = n, fast = n;
do {
slow = sum(slow);
fast = sum(sum(fast));
} while(slow != fast);
return slow == 1;
You are given a large integer represented as an integer array digits, where each digits[i] is the ith digit of the integer. The digits are ordered from most significant to least significant in
left-to-right order. The large integer does not contain any leading 0's.
Increment the large integer by one and return the resulting array of digits.
Example 1:
Example 2:
Input: digits = [4,3,2,1]
Output: [4,3,2,2]
Explanation: The array represents the integer 4321.
Incrementing by one gives 4321 + 1 = 4322.
Thus, the result should be [4,3,2,2].
Example 3:
Constraints:
class Solution {
public int[] plusOne(int[] digits) {
int n = digits.length;
}
}
50. Pow(x, n)
(https://leetcode.com/problems/powx-n/)
Medium
Implement pow(x, n), which calculates x raised to the power n (i.e., xn).
Example 1:
Input: x = 2.00000, n = 10
Output: 1024.00000
Example 2:
Input: x = 2.10000, n = 3
Output: 9.26100
Example 3:
Input: x = 2.00000, n = -2
Output: 0.25000
Explanation: 2-2 = 1/22 = 1/4 = 0.25
Constraints:
Approach
- Recursiom:
- we can divide the power by 2 and same value can be reused
- For non-negative:
- for even: pow(x, n) = pow(x, n/2)*pow(x,n/2)
- for odd: - for even: pow(x, n) = x*pow(x, n/2)*pow(x,n/2)
- For negative:
- for even: pow(x, n) = pow(x, n/2)*pow(x,n/2)
- for odd: - for even: pow(x, n) = 1/x*pow(x, n/2)*pow(x,n/2)
Solution
class Solution {
public double myPow(double x, int n) {
if(n < 0)
return myPowNeg(x, n);
return myPowPos(x, n);
}
Complexity Analysis
- Time Complexity: O(logn)
- Space Complexity: O(logn)
Given two non-negative integers num1 and num2 represented as strings, return the product of num1 and num2, also represented as a string.
Note: You must not use any built-in BigInteger library or convert the inputs to integer directly.
Example 1:
Example 2:
Constraints:
Approach
- Reverse the number strings
- StringBuilder(mutable string) of 400 size, as num1 & num2 of 200 length at max
- calculate the multiplication and store overwrite it at the i+j position
- after each inner loop, we insert the carry at i+j position, j would be 1 position more the the original length of the second number
- reverse the string
- remove all the leading 0s
- return 0 if result string size is zero or else return thr result string
Solution
class Solution {
public String multiply(String num1, String num2) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 400; i++)
sb.append(0);
num1 = reverse(num1);
num2 = reverse(num2);
if(num1.length() > num2.length()) {
String tmp = num1;
num1 = num2;
num2 = tmp;
}
int carry = 0;
int i = 0, j = 0;
for (i = 0; i < num2.length(); i++) {
carry = 0;
for (j = 0; j < num1.length(); j++) {
int a = num2.charAt(i)-'0';
int b = num1.charAt(j)-'0';
int n = a * b + carry;
int prev = sb.charAt(i+j)-'0';
int sum = (prev + n) % 10;
carry = (n+prev) / 10;
sum +='0';
sb.setCharAt(i + j, (char) sum);
}
sb.setCharAt(i+j, (char) (carry+'0'));
}
Complexity Analysis
- Time Compexity: O(n*m)
- Space Complexity: O(400)
Resources
136. Single Number
Easy
Given a non-empty array of integers nums, every element appears twice except for one. Find that single one.
You must implement a solution with a linear runtime complexity and use only constant extra space.
Example 1:
Input: nums = [2,2,1]
Output: 1
Example 2:
Example 3:
Constraints:
class Solution {
public int singleNumber(int[] nums) {
int res = 0;
return res;
}
}
Write a function that takes an unsigned integer and returns the number of '1' bits it has (also known as the Hamming weight).
Note:
Note that in some languages, such as Java, there is no unsigned integer type. In this case, the input will be given as a signed integer type. It should not affect your implementation, as
the integer's internal binary representation is the same, whether it is signed or unsigned. In Java, the compiler represents the signed integers using 2's complement notation.
Therefore, in Example 3, the input represents the signed integer. -3.
Example 1:
Input: n = 00000000000000000000000000001011
Output: 3
Explanation: The input binary string 00000000000000000000000000001011 has a total of three '1' bits.
Example 2:
Input: n = 00000000000000000000000010000000
Output: 1
Explanation: The input binary string 00000000000000000000000010000000 has a total of one '1' bit.
Example 3:
Input: n = 11111111111111111111111111111101
Output: 31
Explanation: The input binary string 11111111111111111111111111111101 has a total of thirty one '1' bits.
Constraints:
The input must be a binary string of length 32.
Follow up: If this function is called many times, how would you optimize it?
while(n != 0) {
n = n & (n-1);
count++;
}
return count;
}
}
Given an integer n, return an array ans of length n + 1 such that for each i (0 <= i <= n), ans[i] is the number of 1's in the binary representation of i.
Example 1:
Input: n = 2
Output: [0,1,1]
Explanation:
0 --> 0
1 --> 1
2 --> 10
Example 2:
Input: n = 5
Output: [0,1,1,2,1,2]
Explanation:
0 --> 0
1 --> 1
2 --> 10
3 --> 11
4 --> 100
5 --> 101
Constraints:
Follow up:
It is very easy to come up with a solution with a runtime of O(n log n). Can you do it in linear time O(n) and possibly in a single pass?
Can you do it without using any built-in function (i.e., like __builtin_popcount in C++)?
class Solution {
public int[] countBits(int n) {
int[] dp = new int[n+1];
int offset = 1;
return dp;
}
}
class Solution {
public int[] countBits(int n) {
int[] dp = new int[n+1];
dp[i] = dp[i/2] + i % 2;
}
return dp;
}
}
Note:
Note that in some languages, such as Java, there is no unsigned integer type. In this case, both input and output will be given as a signed integer type. They should not affect
your implementation, as the integer's internal binary representation is the same, whether it is signed or unsigned. In Java, the compiler represents the signed integers using 2's
complement notation. Therefore, in Example 2 above, the input represents the signed integer -3 and the output represents the signed integer -1073741825.
Example 1:
Input: n = 00000010100101000001111010011100
Output: 964176192 (00111001011110000010100101000000)
Explanation: The input binary string 00000010100101000001111010011100 represents the unsigned integer 43261596, so return 964176192 w
Example 2:
Input: n = 11111111111111111111111111111101
Output: 3221225471 (10111111111111111111111111111111)
Explanation: The input binary string 11111111111111111111111111111101 represents the unsigned integer 4294967293, so return 322122547
Constraints:
Follow up: If this function is called many times, how would you optimize it?
public class Solution {
// you need treat n as an unsigned value
public int reverseBits(int n) {
int res = 0;
for(int i = 0; i < 32; i++) {
int bit = (n >> i) & 1; // check whether the bit is set or not [right shift each bit & 000..1] -> gives the value present
res = res | (bit << (31 - i)); // put the bit at 31 - i th position i.e, reverse
}
return res;
}
}
Given an array nums containing n distinct numbers in the range [0, n], return the only number in the range that is missing from the array.
Example 1:
Example 2:
Example 3:
Constraints:
n == nums.length
1 <= n <= 104
0 <= nums[i] <= n
All the numbers of nums are unique.
Follow up: Could you implement a solution using only O(1) extra space complexity and
O(n) runtime complexity?
class Solution {
public int missingNumber(int[] nums) {
int n = nums.length;
int sum = n * (n + 1) / 2;
Given two integers a and b, return the sum of the two integers without using the operators + and -.
Example 1:
Input: a = 1, b = 2
Output: 3
Example 2:
Input: a = 2, b = 3
Output: 5
Constraints:
Approach
Solution
Complexity Analysis
- Time Complexity:
- Space Complexity:
Resources
class UnionFind {
int[] root;
int[] rank;
UnionFind(int size) {
root = new int[size];
rank = new int[size];
if(rootX != rootY) {
if(rank[rootX] > rank[rootY])
root[rootY] = rootX;
else if(rank[rootX] < rank[rootY])
root[rootX] = rootY;
else {
root[rootY] = rootX;
rank[rootX]++;
}
}
}
You are given a 0-indexed 2D integer array grid of size m x n. Each cell has one of two values:
Return the minimum number of obstacles to remove so you can move from the upper left corner (0, 0) to the lower right corner (m - 1, n - 1).
Example 1:
Input: grid = [[0,1,1],[1,1,0],[1,1,0]]
Output: 2
Explanation: We can remove the obstacles at (0, 1) and (0, 2) to create a path from (0, 0) to (2, 2).
It can be shown that we need to remove at least 2 obstacles, so we return 2.
Note that there may be other ways to remove 2 obstacles to create a path.
Example 2:
Constraints:
m == grid.length
n == grid[i].length
1 <= m, n <= 105
2 <= m * n <= 105
grid[i][j] is either 0 or 1.
grid[0][0] == grid[m - 1][n - 1] == 0
Approach
- Node class to store distance, row number, column number, done processing
- Map to store the key and the node for that key
- priority queue based on distance
- add the source to pq, with distance 0
- while pq not empty, poll a node
- if node is not done
- mark it done
- check all it's neighbour's distance with the node.dsitance+grid[neighbour's row][neighbour's col]
- update the distance of neighbour if it's greater than above calculated distance
- and add the neighbour into the pq
Solution
class Solution {
class Node {
int dist;
int i;
int j;
boolean done;
Node(int d, int ii, int jj, boolean done) {
dist = d;
i = ii;
j = jj;
done = done;
}
}
pq.offer(mp.get("0,0"));
while(!pq.isEmpty()) {
Node node = pq.poll();
if(node.done == false) {
node.done = true;
int i = node.i;
int j = node.j;
for(int[] dir:dirs) {
int new_i = i+dir[0];
int new_j = j+dir[1];
if(new_i >= 0 && new_i < n && new_j >= 0 && new_j < m) {
String neiK = ""+new_i+","+new_j;
Node nei = mp.get(neiK);
int cost = node.dist+grid[new_i][new_j];
if(cost < nei.dist) {
nei.dist = cost;
pq.offer(mp.get(neiK));
}
}
}
}
}
return mp.get(""+(n-1)+","+(m-1)).dist;
}
}
Complexity Analysis
- Time Complexity: O(n*m log (n*m))
- Space Complexity: O(n*m)
BFS on Graph
• Undiscovered – the vertex is in its initial, virgin state.
• Discovered – the vertex has been found, but we have not yet checked out all its incident edges.
• Processed – the vertex after we have visited all of its incident edges
public Graph(int v) {
degree = new int[v];
nvertices = v;
nedges = 0;
adjList = new HashMap<>();
for(int i = 0; i < v; i++) {
adjList.put(i, new ArrayList<>());
}
}
Graph g;
public BfsGraph(Graph g) {
this.g = g;
processed = new boolean[g.nvertices];
discovered = new boolean[g.nvertices];
parent = new int[g.nvertices];
for(int i = 0; i < g.nvertices; i++)
parent[i] = -1;
}
q.offer(start);
discovered[start] = true;
while (!q.isEmpty()) {
v = q.poll();
// process vertex early - v
System.out.println(v);
processed[v] = true;
List<int[]> neighbors = g.adjList.get(v);
for(int[] neighbor : neighbors) {
y = neighbor[0];
if(!processed[y] || g.directed) {
// process edge(v, y)
System.out.println(v+"-"+y);
}
if(!discovered[y]) {
q.offer(y);
discovered[y] = true;
parent[y] = v;
}
}
// process vertex late - v
}
}
However, Dijkstra’s algorithm can fail when the graph has negative edge weights. This is when BF becomes really handy because it can be used to detect negative cycles and
determine where they occur.Finding negative cycles can be useful in many types of applications. One particularly neat application arises in finance when performing an
arbitragebetween two or more markets.
Approach
public class BellmanFordEdgeList {
// A directed edge
public static class Edge {
double cost;
int from, to;
/**
* An implementation of the Bellman-Ford algorithm. The algorithm finds the shortest path between
* a starting node and all other nodes in the graph. The algorithm also detects negative cycles.
* If a node is part of a negative cycle then the minimum cost for that node is set to
* Double.NEGATIVE_INFINITY.
*
* @param edges - An edge list containing directed edges forming the graph
* @param V - The number of vertices in the graph.
* @param start - The id of the starting node
*/
public static double[] bellmanFord(Edge[] edges, int V, int start) {
// Only in the worst case does it take V-1 iterations for the Bellman-Ford
// algorithm to complete. Another stopping condition is when we're unable to
// relax an edge, this means we have reached the optimal solution early.
boolean relaxedAnEdge = true;
Implement strStr().
Given two strings needle and haystack, return the index of the first occurrence of needle in haystack, or -1 if needle is not part of haystack.
Clarification:
What should we return when needle is an empty string? This is a great question to ask during an interview.
For the purpose of this problem, we will return 0 when needle is an empty string. This is consistent to C's strstr() and Java's indexOf().
Example 1:
Constraints:
Approach
- build pattern:
- we build the pattern for the substring
- it would be use in matching the pattern
- how:
- initialize two pointers, starting from 0(j) and 1(i)
- while i < len(substring)
- if s[i] == s[j] then set pattern[i] = j and increment both pointers, (which means we found a suffix that matches a prefix)
- else if j > 0 then set j to pattern[j-1]+1, (j-1 holds the last index where it had a successful match)
- else increment i
- matching pattern
- similar to build pattern
- how:
- initialize two pointers, starting from 0(j) points to sunstring and 0(i) points to string
- while i + len(substring) - j <= len(string)
- if s[i] == s[j]
- if j = len(substring)-1
- we found the match
- increment both pointers,
- else if j > 0 then set j to pattern[j-1]+1, (j-1 holds the last index where it had a successful match)
- else increment i
Solution
class Solution {
public int strStr(String haystack, String needle) {
int[] pattern = new int[needle.length()];
Arrays.fill(pattern, -1);
buildPattern(needle, pattern);
return matchIndex(haystack, needle, pattern);
}
Complexity Analysis
- Time Complexity: O(n+m), n - length of string, m - length of substring
- Space Complexity: O(m), to build the pattern array
Segment Tree
Introduction
Approach
Implementation
class SegmentTree { // the segment tree is stored like a heap array
private int[] st, A;
private int n;
private int left(int p) {
return p << 1;
} // same as binary heap operations
private int right(int p) {
return (p << 1) + 1;
}
// compute the min position in the left and right part of the interval
int p1 = rmq(left(p), L, (L + R) / 2, i, j);
int p2 = rmq(right(p), (L + R) / 2 + 1, R, i, j);
Complexity Analysis
- Time Complexity:
- Space Complexity:
Fenwick Tree
Introduction
Approach
Implementation
class FenwickTree {
int[] ft, nums;
Complexity Analysis
- Time Complexity:
- Space Complexity:
Fenwick Tree
Introduction
Approach
Implementation
public class FenwickTree2D {
int[][] ft;
public int rangeSum(int x1, int y1, int x2, int y2) {
// Inclusion & Exclusion principle
return querySum(x2, y2) - querySum(x1 - 1, y2) - querySum(x2, y1 - 1) + querySum(x1 - 1, y1 - 1);
}
}
Complexity Analysis
- Time Complexity:
- Space Complexity:
NeetCode-150
1. Arrays & Hashing Resources
(https://github.com/dipjul/NeetCode-
150/blob/main/01.%20Arrays%20&%20Hashing/)
1. Contains Duplicate Solution (https://github.com/dipjul/NeetCode-150/blob/main/01.%20Arrays%20&%20Hashing/01.%20ContainsDuplicate.md)
2. Valid Anagram Solution (https://github.com/dipjul/NeetCode-150/blob/main/01.%20Arrays%20&%20Hashing/02.ValidAnagram.md)
3. Two Sum Solution (https://github.com/dipjul/NeetCode-150/blob/main/01.%20Arrays%20&%20Hashing/03.TwoSum.md)
4. Group Anagrams Solution (https://github.com/dipjul/NeetCode-150/blob/main/01.%20Arrays%20&%20Hashing/04.GroupAnagrams.md)
5. Top K Frequent Elements Solution (https://github.com/dipjul/NeetCode-150/blob/main/01.%20Arrays%20&%20Hashing/05.TopKElements.md)
6. Product of Array Except Self Solution (https://github.com/dipjul/NeetCode-150/blob/main/01.%20Arrays%20&%20Hashing/06.ProductOfArrayExceptSelf.md)
7. Valid Sudoku Solution (https://github.com/dipjul/NeetCode-150/blob/main/01.%20Arrays%20&%20Hashing/07.ValidSodoku.md)
8. Encode And Decode Strings Solution (https://github.com/dipjul/NeetCode-150/blob/main/01.%20Arrays%20&%20Hashing/08.EncodeAndDecodeStrings.md)
9. Longest Consecutive Sequence Solution (https://github.com/dipjul/NeetCode-150/blob/main/01.%20Arrays%20&%20Hashing/09.LongestConsecutiveSequence.md)