Array
- Rotate Elements by K
- Right rotation by K:
- Reverse entire array
- Reverse the first âkâ elements
- Reverse the rest (from k to end)
- Left rotation by K:
- Reverse the first âkâ elements
- Reverse the rest (from k to end)
- Reverse entire array
Code
fun rotate(nums: IntArray, kk: Int): Unit { val n = nums.size val k = kk%n reverse(nums,0,n-1) reverse(nums,0,k-1) reverse(nums,k,n-1) } fun reverse(nums: IntArray, s: Int, e: Int){ var start = s var end = e while(start<end){ nums[start] = nums[end].also { nums[end] = nums[start]} start++ end-- } } - Right rotation by K:
- *Contains Duplicate
- Brute Force:
Use Two loops- TC: O(N^2)
- Better:
Sort()- TC: O(N*logN)
- Optimal:
HashSet or HashMap- TC: O(N), SC: O(N)
- Brute Force:
- Search in Rotated Sorted Array
- Use binary search and keep moving start and end based on sorted part conditions
Code
fun search(nums: IntArray, x: Int): Int { var n = nums.size var start = 0 var end = n-1 while(start<=end){ val mid = (start+end)/2 if(nums[mid]==x) return mid if(nums[start]<=nums[mid]){ //left half is sorted if(nums[start]<=x && x<nums[mid]){ //element is sorted part end = mid-1 }else{ start = mid+1 } }else{ //right half is sorted if(nums[mid]<x && x<=nums[end]){ //element is sorted part start = mid+1 }else{ end = mid-1 } } } return -1 } - *Insert Interval
- Optimal:
- Add all intervals ending before newOne start
- Merge the overlapping ones
- Add the rest left over intervals
Code
fun insert(intervals: Array<IntArray>, newInterval: IntArray): Array<IntArray> { var n = intervals.size val ans = mutableListOf<IntArray>() //add intervals ending before newOne var i = 0 while(i<n && intervals[i][1]<newInterval[0]){ ans.add(intervals[i]) i++ } //merge the overlapping ones var start = newInterval[0] var end = newInterval[1] while(i<n && intervals[i][0]<=end){ start = minOf(intervals[i][0],start) end = maxOf(intervals[i][1],end) i++ } ans.add(intArrayOf(start,end)) //add the rest intervals while(i<n){ ans.add(intervals[i]) i++ } return ans.toTypedArray() } - Optimal:
- Non-overlapping Intervals
- Optimal:
- Sort by end
- Create pairEnd and update it based on
if(intervals[0] >= pairEnd)
Code
fun eraseOverlapIntervals(intervals: Array<IntArray>): Int { intervals.sortBy { it[1] } var count = 0 var pairEnd = Int.MIN_VALUE for(interval in intervals){ if(interval[0]>=pairEnd){ pairEnd = interval[1] }else{ count++ } } return count } - Optimal:
- Product of Array Except Self
- Optimal:
- Create Prefix Array, & Postfix Array
- Merge them to create Output Array
- TC: O(3N), SC: O(2N) (excluding output array)
- Optmial More:
- Create output array, store Prefix product first and then update with PostFix
- TC: O(2*N), SC: O(1)
Code
fun productExceptSelf(nums: IntArray): IntArray { var n = nums.size var output = IntArray(n) var prefix = 1 for(i in 0 until n){ output[i] = prefix prefix *= nums[i] } var postfix = 1 for(i in n-1 downTo 0){ output[i] *= postfix postfix *= nums[i] } return output } - Optimal:
- Container With Most Water
- Use Two pointers, start and end and fetch height of left and right
- store max in
ans=maxOf(ans, (end-start)*minOf(left,right))
Code
fun maxArea(height: IntArray): Int { var start = 0 var end = height.size-1 var ans = 0 while(start<end){ var left = height[start] var right = height[end] ans = maxOf(ans, (end-start)*minOf(left,right)) if(left>right){ end-- }else{ start++ } } return ans } - Daily Temperatures
Code
fun dailyTemperatures(arr: IntArray): IntArray { var n = arr.size var result = IntArray(n){0} var stack = Stack<Int>() for(i in arr.indices){ while(stack.isNotEmpty() && arr[stack.peek()]<arr[i]){ var index = stack.pop() result[index] = i-index } stack.push(i) } return result } - Next Greater Element I
Code
fun nextGreaterElement(nums1: IntArray, nums2: IntArray): IntArray { val n = nums1.size var map = hashMapOf<Int,Int>() var stack = Stack<Int>() for(num in nums2){ while(stack.isNotEmpty() && stack.peek() < num){ map.put(stack.pop(), num) } stack.push(num) } for(i in nums1.indices){ nums1[i] = map.getOrDefault(nums1[i], -1) } return nums1 } - Next Greater Element II
Code
fun nextGreaterElements(nums: IntArray): IntArray { var stack = Stack<Int>() val n = nums.size var res = IntArray(n){-1} for(i in 0 until n*2){ var curIndex = i%n while(stack.isNotEmpty() && nums[stack.peek()] < nums[curIndex]){ var index = stack.pop() res[index] = nums[curIndex] } if(i<n){ stack.push(curIndex) } } return res } - Grid Unique Paths II
Code
fun uniquePathsWithObstacles(grid: Array<IntArray>): Int { var row = grid.size var col = grid[0].size val arr = IntArray(col) arr[0] = 1 for(i in 0 until row){ for(j in 0 until col){ if(grid[i][j]==1){ arr[j] = 0 }else if(j>0){ arr[j] = arr[j] + arr[j-1] } } } return arr[col-1] } - Spiral Matrix
Code
fun spiralOrder(matrix: Array<IntArray>): List<Int> { var col = matrix[0].size var row = matrix.size var top = 0 var left = 0 var bottom = row-1 var right = col-1 var ans = mutableListOf<Int>() while(top<=bottom && left<=right){ for(i in left..right) ans.add(matrix[top][i]) top++ for(i in top..bottom) ans.add(matrix[i][right]) right-- if(top<=bottom) { for(i in right downTo left) ans.add(matrix[bottom][i]) bottom-- } if(left<=right) { for(i in bottom downTo top) ans.add(matrix[i][left]) left++ } } return ans }
String
Binary Search
HashMap
###