├── .gitignore
├── .idea
├── .gitignore
├── kotlinc.xml
├── leetcode
│ └── editor.xml
├── libraries
│ └── KotlinJavaRuntime.xml
├── misc.xml
└── vcs.xml
├── LeetCodeKotlin.iml
├── README.md
└── src
└── com
└── boycoder
├── Main.kt
├── basis
├── Basis.kt
├── algorithm
│ ├── BasicAlgorithm.kt
│ ├── BinarySearch.kt
│ └── sort
│ │ ├── BubbleSort.kt
│ │ ├── CountSort.kt
│ │ ├── HeapSort.kt
│ │ ├── MergeSort.kt
│ │ └── SelectionSort.kt
└── datastructure
│ ├── BinaryHeap.kt
│ ├── ListNode.kt
│ ├── TreeNode.kt
│ ├── UnionFindQuickFind.kt
│ └── UnionFindQuickUnion.kt
├── problems
├── LeetCode.kt
├── array
│ ├── Easy_27_RemoveElement.kt
│ ├── Med_1248_CountNiceSubArray.kt
│ ├── Med_209_MinSizeSubArray.kt
│ ├── Med_325_MaxSizeSubArray.kt
│ ├── Med_523_ContinuousSubArraySumK.kt
│ ├── Med_560_SubArrayEqualK.kt
│ ├── Med_713_SubArrayLessK.kt
│ └── Med_974_SubArraySumDivisiableK.kt
├── backtrack
│ ├── Hard_51_NQueens.kt
│ ├── Med_077_Combinations.kt
│ ├── Med_131_PalindromePartition.kt
│ ├── Med_17_LetterCombinationPhoneNum.kt
│ ├── Med_216_CombinationSumIII.kt
│ ├── Med_332_ReconstructItinerary.kt
│ ├── Med_39_CombinationSum.kt
│ ├── Med_40_CombinationSumII.kt
│ ├── Med_46_Permutations.kt
│ ├── Med_47_PermutationsII.kt
│ ├── Med_491_IncreasingSubSequences.kt
│ ├── Med_78_SubSet.kt
│ ├── Med_90_SubSetII.kt
│ └── Med_93_RestoreIPAddress.kt
├── bst
│ ├── Easy_108_ArrayToBST.kt
│ ├── Easy_235_LowestCommonAncestorBST.kt
│ ├── Easy_501_ModeInBST.kt
│ ├── Easy_530_AbsDifferenceInBST.kt
│ ├── Easy_700_SearchInBST.kt
│ ├── Med_450_DeleteInBST.kt
│ ├── Med_538_BSTToGreaterTree.kt
│ ├── Med_669_TrimBST.kt
│ ├── Med_701_InsertIntoBST.kt
│ └── Med_98_ValidateBST.kt
├── dp
│ ├── Easy_062_UniquePath.kt
│ ├── Easy_070_ClimbStairs.kt
│ ├── Easy_509_Fibonacci.kt
│ ├── Easy_746_ClimbStairsCost.kt
│ ├── Med_063_UniquePathII.kt
│ ├── Med_096_UniqueBST.kt
│ ├── Med_343_IntegerBreak.kt
│ ├── editdistance
│ │ ├── Easy_392_IsSubSequence.kt
│ │ ├── Hard_115_DistinctSubSequence.kt
│ │ ├── Hard_72_EditDistance.kt
│ │ ├── Med_583_DeleteForTwoString.kt
│ │ └── Med_647_PalindromicSubString.kt
│ ├── knapsack
│ │ ├── Med_1049_LastStoneWeight.kt
│ │ ├── Med_139_WordBreak.kt
│ │ ├── Med_279_PerfectSquares.kt
│ │ ├── Med_322_CoinChange.kt
│ │ ├── Med_377_CombinationSumIV.kt
│ │ ├── Med_416_SubSetSum.kt
│ │ ├── Med_474_ZeroAndOne.kt
│ │ ├── Med_494_TargetSum.kt
│ │ └── Med_518_CoinChangeII.kt
│ ├── robber
│ │ ├── Med_198_HouseRobber.kt
│ │ ├── Med_213_HouseRobberII.kt
│ │ └── Med_337_HouseRobberIII.kt
│ ├── stock
│ │ ├── Med_121_SellStock.kt
│ │ ├── Med_122_SellStockII.kt
│ │ ├── Med_123_SellStockIII.kt
│ │ ├── Med_188_SellStockIV.kt
│ │ ├── Med_309_SellStockCoolDown.kt
│ │ └── Med_714_SellStockFee.kt
│ └── subsequence
│ │ ├── Easy_53_MaxSubArray.kt
│ │ ├── Med_1035_UncrossedLines.kt
│ │ ├── Med_1143_LongestCommonSubsequence.kt
│ │ ├── Med_300_LongestIncreasingSubsequence.kt
│ │ ├── Med_674_LongestIncreasingSubsequenceII.kt
│ │ └── Med_718_LongestSubArray.kt
├── greedy
│ └── Easy_445_AssignCookie.kt
├── hash
│ ├── Easy_001_TwoSum.kt
│ ├── Easy_202_HappyNumber.kt
│ ├── Easy_242_Anagram.kt
│ ├── Easy_349_IntersectionTwoArray.kt
│ ├── Med_15_3Sum.kt
│ ├── Med_18_4Sum.kt
│ ├── Med_383_RansomNote.kt
│ └── Med_454_FourSum.kt
├── linkedList
│ ├── Easy_203_RemoveLinkedListElements.kt
│ ├── Easy_206_ReverseLinkedList.kt
│ ├── Med_19_RemoveNthFromEnd.kt
│ └── Med_24_SwapNodeInPair.kt
├── monotone
│ ├── Easy_155_MinStack.kt
│ ├── Hard_42_TrapRainWater.kt
│ ├── Med_1438_LongestSubArrayLimitedAbs.kt
│ ├── Med_739_DailyTemperatures.kt
│ └── Med_MaxQueue.kt
├── pointers
│ └── Easy_35_SearchInsertPosition.kt
├── stack
│ ├── Easy_1047_RemoveDuplicate.kt
│ ├── Easy_20_ValidParentheses.kt
│ ├── Easy_225_ImpStackUseQueue.kt
│ ├── Easy_232_ImpQueueUseStack.kt
│ ├── Hard_239_SlidingWindowMax.kt
│ ├── Med_150_ReversePolishNotation.kt
│ └── Med_347_TopKFrequentElements.kt
├── string
│ ├── Easy_28_ImplementStr.kt
│ ├── Easy_344_ReverseString.kt
│ └── Med_151_ReverseWordInString.kt
└── tree
│ ├── Easy_101_SymmetricTree.kt
│ ├── Easy_104_MaxDepthBinaryTree.kt
│ ├── Easy_110_BalancedBinaryTree.kt
│ ├── Easy_111_MinDepthBinaryTree.kt
│ ├── Easy_112_PathSum.kt
│ ├── Easy_144_BinaryTreePreorder.kt
│ ├── Easy_145_BinaryTreePostorderTraversal.kt
│ ├── Easy_226_InvertBinaryTree.kt
│ ├── Easy_257_BinaryTreePaths.kt
│ ├── Easy_404_SumOfLeftLeaves.kt
│ ├── Easy_559_MaxDepthNAryTree.kt
│ ├── Easy_617_MergeTwoBinaryTree.kt
│ ├── Easy_94_BinaryTreeInorderTraversal.kt
│ ├── Med_102_BinaryTreeLevelOrderTraversal.kt
│ ├── Med_106_ConstructBinaryTree.kt
│ ├── Med_222_CompleteTreeNodeCount.kt
│ ├── Med_236_LowestCommonAncestor.kt
│ ├── Med_513_BottomLeftTreeValue.kt
│ └── Med_654_MaxBinaryTree.kt
└── utils
├── Utils.kt
└── WrongResultException.kt
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled class file
2 | *.class
3 |
4 | # Log file
5 | *.log
6 |
7 | # BlueJ files
8 | *.ctxt
9 |
10 | # Mobile Tools for Java (J2ME)
11 | .mtj.tmp/
12 |
13 | # Package Files #
14 | *.jar
15 | *.war
16 | *.nar
17 | *.ear
18 | *.zip
19 | *.tar.gz
20 | *.rar
21 |
22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
23 | hs_err_pid*
24 |
25 | # Java class files
26 | *.class
27 |
28 | # Generated files
29 | bin/
30 | gen/
31 | out/
32 | # Uncomment the following line in case you need and you don't have the release build type files in your app
33 | # release/
34 |
35 | # Gradle files
36 | .gradle/
37 | build/
38 |
39 | # Log Files
40 | *.log
41 |
42 | # Android Studio 3 in .gitignore file.
43 | .idea/caches
44 | .idea/modules.xml
45 | # Comment next line if keeping position of elements in Navigation Editor is relevant for you
46 | .idea/navEditor.xml
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/.idea/kotlinc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/leetcode/editor.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
24 |
25 |
--------------------------------------------------------------------------------
/.idea/libraries/KotlinJavaRuntime.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/LeetCodeKotlin.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/com/boycoder/Main.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder
2 |
3 |
--------------------------------------------------------------------------------
/src/com/boycoder/basis/Basis.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.basis
2 |
3 |
--------------------------------------------------------------------------------
/src/com/boycoder/basis/algorithm/BasicAlgorithm.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.basis.algorithm
2 |
3 | /**
4 | * @Author: zhutao
5 | * @datetime: 2021/6/4
6 | * @desc:
7 | */
--------------------------------------------------------------------------------
/src/com/boycoder/basis/algorithm/sort/BubbleSort.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.basis.algorithm.sort
2 |
3 | import com.boycoder.utils.asserts
4 | import com.boycoder.utils.isSorted
5 | import kotlin.random.Random
6 |
7 | /**
8 | * @Author: zhutao
9 | * @datetime: 2021/6/4
10 | *
11 | * @desc: The basic ideal of bubble sort is, compare every pair of element,
12 | * make sure the biggest element go to the end.
13 | * eg: 6,4,5,1,5
14 | * | |
15 | * swap
16 | * 4,6,5,1,5
17 | * | |
18 | * 4,5,6,1,5
19 | * | |
20 | * 4,5,1,6,5
21 | * | |
22 | * 4,5,1,5,6
23 | * | |
24 | * 4,5,1,5
25 | * | |
26 | * Time: O(N^2)
27 | * Space: O(1)
28 | * In-Place: Yes
29 | * Stable: Yes
30 | */
31 | object BubbleSort {
32 | fun sort(array: IntArray): IntArray {
33 | return sort3(array)
34 | }
35 |
36 | /**
37 | * Bubble sort + optimize
38 | * For the case that the tail elements already sorted,
39 | * we can just skip.
40 | */
41 | private fun sort2(array: IntArray): IntArray {
42 | var end = array.size - 1
43 |
44 | while (end >= 1) {
45 | var endIndex = 1
46 | for (begin in 1..end) {
47 | if (array[begin - 1] > array[begin]) {
48 | val temp = array[begin - 1]
49 | array[begin - 1] = array[begin]
50 | array[begin] = temp
51 |
52 | endIndex = begin
53 | }
54 | }
55 | end = endIndex
56 | end--
57 | }
58 |
59 | return array
60 | }
61 |
62 | // Basic bubble sort with while
63 | private fun sort3(array: IntArray): IntArray {
64 | var end = array.size - 1
65 |
66 | while (end >= 1) {
67 | var begin = 1
68 | while (begin <= end) {
69 | if (array[begin - 1] > array[begin]) {
70 | val temp = array[begin - 1]
71 | array[begin - 1] = array[begin]
72 | array[begin] = temp
73 | }
74 | begin++
75 | }
76 | end--
77 | }
78 |
79 | return array
80 | }
81 |
82 | // Basic bubble sort
83 | private fun sort1(array: IntArray): IntArray {
84 | for (end in (array.size - 1) downTo 1) {
85 | for (begin in 1..end) {
86 | if (array[begin - 1] > array[begin]) {
87 | val temp = array[begin - 1]
88 | array[begin - 1] = array[begin]
89 | array[begin] = temp
90 | }
91 | }
92 | }
93 |
94 | return array
95 | }
96 | }
97 |
98 | fun main() {
99 | val array = (1..100).shuffled().toIntArray()
100 | val res = isSorted(BubbleSort.sort(array))
101 | asserts(res, true)
102 | }
--------------------------------------------------------------------------------
/src/com/boycoder/basis/algorithm/sort/CountSort.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.basis.algorithm.sort
2 |
3 | import com.boycoder.utils.asserts
4 | import com.boycoder.utils.isSorted
5 |
6 | /**
7 | * @Author: zhutao
8 | * @datetime: 2021/6/4
9 | * @desc: The ideal of count sort is a trade-off between time and space
10 | */
11 | object CountSort {
12 | fun sort(array: IntArray, max: Int): IntArray {
13 | val count = IntArray(max + 1)
14 | for (i in array) {
15 | count[i]++
16 | }
17 | val list = mutableListOf()
18 | for (i in 0 until count.size) {
19 | for (j in 1..count[i]) {
20 | list.add(i)
21 | }
22 | }
23 | return list.toIntArray()
24 | }
25 | }
26 |
27 | fun main() {
28 | val array = (1..100).shuffled().toIntArray()
29 | val res = isSorted(CountSort.sort(array, 100))
30 | asserts(res, true)
31 | }
--------------------------------------------------------------------------------
/src/com/boycoder/basis/algorithm/sort/HeapSort.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.basis.algorithm.sort
2 |
3 | import com.boycoder.basis.datastructure.BinaryHeap
4 | import com.boycoder.utils.asserts
5 | import com.boycoder.utils.isSorted
6 |
7 | /**
8 | * @Author: zhutao
9 | * @datetime: 2021/6/4
10 | * @desc:
11 | */
12 | object HeapSort {
13 | fun sort(array: IntArray): IntArray {
14 |
15 | // min heap
16 | val heap = BinaryHeap{o1, o2 -> o2 -o1}
17 |
18 | for (i in array) {
19 | heap.add(i)
20 | }
21 |
22 | val list = mutableListOf()
23 | repeat(heap.size()) {
24 | list.add(heap.remove())
25 | }
26 |
27 | return list.toIntArray()
28 | }
29 | }
30 |
31 | fun main() {
32 | val array = (1..100).shuffled().toIntArray()
33 | val res = isSorted(HeapSort.sort(array))
34 | asserts(res, true)
35 | }
--------------------------------------------------------------------------------
/src/com/boycoder/basis/algorithm/sort/MergeSort.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.basis.algorithm.sort
2 |
3 | import com.boycoder.utils.asserts
4 | import com.boycoder.utils.isSorted
5 |
6 | /**
7 | * @Author: zhutao
8 | * @datetime: 2021/6/4
9 | * @desc: The ideal of merge sort is, Divide Conquer
10 | * We divide the array into many parts, and merge them to sort
11 | *
12 | * Time: O(NLogN)
13 | * Space: O(N)
14 | * In-Place: No
15 | * Stable: Yes
16 | */
17 | object MergeSort {
18 | fun sort(array: IntArray): IntArray {
19 | mergeSort(array, 0, array.size - 1)
20 | return array
21 | }
22 |
23 | private fun mergeSort(array: IntArray, begin: Int, end: Int) {
24 | if (end - begin < 1) {
25 | // there is only one element
26 | return
27 | }
28 |
29 | val mid = begin + (end - begin) / 2
30 |
31 | // divide
32 | mergeSort(array, begin, mid)
33 | mergeSort(array, mid + 1, end)
34 |
35 | // conquer
36 | merge(array, begin, mid, end)
37 | }
38 |
39 | /**
40 | * [begin, mid]
41 | * [mid + 1, end]
42 | */
43 | private fun merge(array: IntArray, begin: Int, mid: Int, end: Int) {
44 | val backup = array.slice(begin..mid)
45 | var cur = begin
46 | var leftCur = 0
47 | var rightCur = mid + 1
48 |
49 | while (cur <= end) {
50 | // 1. pick left
51 | // 2. right side out of index
52 | if (rightCur > end || (leftCur < backup.size && backup[leftCur] < array[rightCur])) {
53 | array[cur] = backup[leftCur]
54 | leftCur++
55 | } else {
56 | array[cur] = array[rightCur]
57 | rightCur++
58 | }
59 | cur++
60 | }
61 | }
62 | }
63 |
64 | fun main() {
65 | val array = (1..100).shuffled().toIntArray()
66 | val res = isSorted(MergeSort.sort(array))
67 | asserts(res, true)
68 | }
--------------------------------------------------------------------------------
/src/com/boycoder/basis/algorithm/sort/SelectionSort.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.basis.algorithm.sort
2 |
3 | import com.boycoder.utils.asserts
4 | import com.boycoder.utils.isSorted
5 |
6 | /**
7 | * @Author: zhutao
8 | * @datetime: 2021/6/4
9 | * @desc: Selection sort is like Bubble sort, but it dont swap every time.
10 | * Instead of swapping, we mark the max index, and swap it with the end.
11 | * Time: O(N^2)
12 | * Space: O(1)
13 | * In-Place: Yes
14 | * Stable: No
15 | */
16 | object SelectionSort {
17 | fun sort(array: IntArray): IntArray {
18 | for (end in (array.size - 1) downTo 1) {
19 |
20 | var maxIndex = 0
21 | for (begin in 1..end) {
22 | if (array[begin] > array[maxIndex]) {
23 | // mark max index
24 | maxIndex = begin
25 | }
26 | }
27 |
28 | // swap
29 | val temp = array[maxIndex]
30 | array[maxIndex] = array[end]
31 | array[end] = temp
32 | }
33 |
34 | return array
35 | }
36 | }
37 |
38 | fun main() {
39 | val array = (1..100).shuffled().toIntArray()
40 | val res = isSorted(SelectionSort.sort(array))
41 | asserts(res, true)
42 | }
--------------------------------------------------------------------------------
/src/com/boycoder/basis/datastructure/ListNode.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.basis.datastructure
2 |
3 | /**
4 | * @Author: zhutao
5 | * @datetime: 2021/6/4
6 | * @desc: Node for LinkedList
7 | */
8 | data class ListNode(var value: Int, var next: ListNode?)
--------------------------------------------------------------------------------
/src/com/boycoder/basis/datastructure/TreeNode.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.basis.datastructure
2 |
3 | /**
4 | * @Author: zhutao
5 | * @datetime: 2021/6/4
6 | * @desc:
7 | */
8 | data class TreeNode(var value: Int, var left: TreeNode? = null, var right: TreeNode? = null)
--------------------------------------------------------------------------------
/src/com/boycoder/basis/datastructure/UnionFindQuickFind.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.basis.datastructure
2 |
3 | /**
4 | * @Author: zhutao
5 | * @datetime: 2021/6/22
6 | * @desc: Quick Find
7 | *
8 | * 1. find O(1)
9 | * 2. union O(n)
10 | */
11 | class UnionFindQuickFind(capacity: Int): IUnionFind {
12 |
13 | private var parents: IntArray
14 |
15 | init {
16 | if (capacity <= 0) {
17 | throw IllegalArgumentException("Capacity must > 0")
18 | }
19 | parents = IntArray(capacity)
20 |
21 | // init, let every element point to itself
22 | for (i in 0 until capacity) {
23 | parents[i] = i
24 | }
25 | }
26 |
27 | override fun find(element: Int): Int {
28 | rangeCheck(element)
29 |
30 | return parents[element]
31 | }
32 |
33 | /**
34 | * Quick find.
35 | *
36 | * 2 4
37 | * 0 1 3
38 | * |
39 | * |
40 | * 4
41 | * 0 1 2 3
42 | *
43 | * Merge element1 and it's children into element2 parents
44 | * This way, find will be really quick, but union is slow.
45 | */
46 | override fun union(element1: Int, element2: Int) {
47 | val p1 = find(element1)
48 | val p2 = find(element2)
49 |
50 | // already union
51 | if (p1 == p2) return
52 |
53 | for (i in 0 until parents.size) {
54 | if (parents[i] == p1) {
55 | parents[i] = p2
56 | }
57 | }
58 | }
59 |
60 | override fun isSame(element1: Int, element2: Int): Boolean {
61 | return find(element1) == find(element2)
62 | }
63 |
64 | private fun rangeCheck(element: Int) {
65 | if (element < 0 || element >= parents.size) {
66 | throw IllegalArgumentException("Out of range")
67 | }
68 | }
69 | }
70 |
71 | interface IUnionFind {
72 | fun find(element: Int): Int
73 | fun union(element1: Int, element2: Int)
74 | fun isSame(element1: Int, element2: Int): Boolean
75 | }
--------------------------------------------------------------------------------
/src/com/boycoder/basis/datastructure/UnionFindQuickUnion.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.basis.datastructure
2 |
3 | /**
4 | * @Author: zhutao
5 | * @datetime: 2021/6/22
6 | * @desc: Quick Union
7 | *
8 | * 1. find O(logn)
9 | * 2. union O(logn)
10 | */
11 | class UnionFindQuickUnion(capacity: Int): IUnionFind {
12 |
13 | private var parents: IntArray
14 |
15 | init {
16 | if (capacity <= 0) {
17 | throw IllegalArgumentException("Capacity must > 0")
18 | }
19 | parents = IntArray(capacity)
20 |
21 | // init, let every element point to itself
22 | for (i in 0 until capacity) {
23 | parents[i] = i
24 | }
25 | }
26 |
27 | /**
28 | * For Quick Union
29 | * Find is slower.
30 | */
31 | override fun find(element: Int): Int {
32 | rangeCheck(element)
33 |
34 | var temp = element
35 | while (temp != parents[temp]) {
36 | temp = parents[temp]
37 | }
38 |
39 | return temp
40 | }
41 |
42 | /**
43 | * Quick Union
44 | *
45 | * This case, we just let element1's parent point to element2's parent
46 | */
47 | override fun union(element1: Int, element2: Int) {
48 | val p1 = find(element1)
49 | val p2 = find(element2)
50 |
51 | // already union
52 | if (p1 == p2) return
53 | parents[p1] = p2
54 | }
55 |
56 | override fun isSame(element1: Int, element2: Int): Boolean {
57 | return find(element1) == find(element2)
58 | }
59 |
60 | private fun rangeCheck(element: Int) {
61 | if (element < 0 || element >= parents.size) {
62 | throw IllegalArgumentException("Out of range")
63 | }
64 | }
65 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/LeetCode.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems
2 |
3 |
--------------------------------------------------------------------------------
/src/com/boycoder/problems/array/Easy_27_RemoveElement.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.array
2 |
3 | /**
4 | * @Author: zhutao
5 | * @datetime: 2021/6/4
6 | * @desc:
7 | */
8 | object Easy_27_RemoveElement {
9 |
10 | /**
11 | * Two pointer start from two side of array
12 | */
13 | fun remove(array: IntArray, target: Int): Int {
14 | var left = 0
15 | var right = array.size - 1
16 |
17 | while (left <= right) {
18 | if (array[right] == target) {
19 | right--
20 | continue
21 | }
22 | if (array[left] == target) {
23 | array[left] = array[right]
24 | right--
25 | left++
26 | } else {
27 | left++
28 | }
29 | }
30 |
31 | return right + 1
32 | }
33 |
34 | /**
35 | * Two point: slow and fast, start from beginning
36 | */
37 | fun remove1(array: IntArray, target: Int): Int {
38 | var slow: Int = 0
39 | var fast: Int = 0
40 |
41 | val size = array.size
42 |
43 | while (fast < size && slow <= fast) {
44 | if (array[fast] == target) {
45 | fast++
46 | } else {
47 | if (slow != fast) {
48 | array[slow] = array[fast]
49 | }
50 |
51 | fast++
52 | slow++
53 | }
54 | }
55 |
56 | return slow
57 | }
58 |
59 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/array/Med_1248_CountNiceSubArray.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.array
2 |
3 | import com.boycoder.utils.asserts
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/21
8 | * @desc: https://leetcode-cn.com/problems/count-number-of-nice-subarrays/
9 | * Brute force
10 | * slide window
11 | */
12 | object Med_1248_CountNiceSubArray {
13 | fun numberOfSubarrays(nums: IntArray, k: Int): Int {
14 | return count(nums, k)
15 | }
16 |
17 | private fun count(nums: IntArray, k: Int): Int {
18 | var count = 0
19 | var presum = 0
20 | //
21 | var map = hashMapOf()
22 | map[0] = 1
23 |
24 | for (right in 0 until nums.size) {
25 | presum = presum + (nums[right] and 1)
26 |
27 | if (map.containsKey(presum - k)) {
28 | count = count + map[presum - k]!!
29 | }
30 |
31 | map.put(presum, map.getOrDefault(presum, 0) + 1)
32 | }
33 |
34 | return count
35 | }
36 | }
37 |
38 | fun main() {
39 | val res = Med_1248_CountNiceSubArray.numberOfSubarrays(intArrayOf(1,1,2,1,1), 3)
40 | asserts(res, 2)
41 | val res1 = Med_1248_CountNiceSubArray.numberOfSubarrays(intArrayOf(2,4,6), 1)
42 | asserts(res1, 0)
43 | val res2 = Med_1248_CountNiceSubArray.numberOfSubarrays(intArrayOf(2,2,2,1,2,2,1,2,2,2), 2)
44 | asserts(res2, 16)
45 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/array/Med_209_MinSizeSubArray.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.array
2 |
3 | import com.boycoder.utils.asserts
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/21
8 | * @desc: https://leetcode-cn.com/problems/minimum-size-subarray-sum/
9 | */
10 | object Med_209_MinSizeSubArray {
11 | fun minSubArrayLen(target: Int, nums: IntArray): Int {
12 | return min2(target, nums)
13 | }
14 |
15 | /**
16 | * slide window
17 | */
18 | private fun min2(target: Int, nums: IntArray): Int {
19 | var left = 0
20 | var sum = 0
21 | var min = Int.MAX_VALUE
22 |
23 | for (right in 0 until nums.size) {
24 | sum = sum + nums[right]
25 |
26 | while (sum >= target) {
27 | min = Math.min(min, right - left + 1)
28 | sum = sum - nums[left]
29 | left++
30 | }
31 | }
32 |
33 | return min
34 | }
35 |
36 | /**
37 | * Brute Force
38 | */
39 | private fun min(target: Int, nums: IntArray): Int {
40 | var min = Int.MAX_VALUE
41 | for(i in 0 until nums.size) {
42 | for (j in i until nums.size) {
43 | // sum
44 | var sum = 0
45 | for (k in i..j) {
46 | sum = sum + nums[k]
47 | }
48 | if (sum >= target) {
49 | min = Math.min(min, j - i + 1)
50 | }
51 | }
52 | }
53 |
54 | return if (min == Int.MAX_VALUE) 0 else min
55 | }
56 |
57 | /**
58 | * Two pointer
59 | */
60 | private fun min1(target: Int, nums: IntArray): Int {
61 | if (nums.size == 0) return 0
62 |
63 | var left = 0
64 | var right = 0
65 | var sum = nums[0]
66 | var min = Int.MAX_VALUE
67 |
68 | while (right < nums.size && left < nums.size) {
69 | if (sum >= target) {
70 | min = Math.min(min, right - left + 1)
71 | sum = sum - nums[left]
72 | left++
73 | } else {
74 | right++
75 | if (right == nums.size) break
76 | sum = sum + nums[right]
77 | }
78 | }
79 |
80 | return if (min == Int.MAX_VALUE) 0 else min
81 | }
82 | }
83 |
84 | fun main() {
85 | val res = Med_209_MinSizeSubArray.minSubArrayLen(7, intArrayOf(2,3,1,2,4,3))
86 | asserts(res, 2)
87 | val res1 = Med_209_MinSizeSubArray.minSubArrayLen(4, intArrayOf(1,4,4))
88 | asserts(res1, 1)
89 | val res2 = Med_209_MinSizeSubArray.minSubArrayLen(11, intArrayOf(1,1,1,1,1,1,1,1))
90 | asserts(res2, 0)
91 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/array/Med_325_MaxSizeSubArray.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.array
2 |
3 | import com.boycoder.utils.asserts
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/21
8 | * @desc: https://leetcode-cn.com/problems/maximum-size-subarray-sum-equals-k/
9 | * Brute force
10 | * Prefix sum
11 | */
12 | object Med_325_MaxSizeSubArray {
13 |
14 | /**
15 | * ----------sum[i]---------------
16 | * ------prefix[j]-------
17 | * ----k----
18 | * length = i - j
19 | *
20 | *
21 | * [1, -1, 5, -2, 3]
22 | * sum [0,1, 0, 5, 3, 6]
23 | * map [0 to 0, 1 to 1, 5 to 3, 3 to 4, 6 to 5]
24 | *
25 | * j from end to 1
26 | * j = 5 sum[5] - k = 3, map[3] = 4, max = 5 - 4
27 | * j = 4 sum[4] - k = 0, map[0] = 0, max = 4 - 0
28 | * j = 3 sum[3] - k = 2, map[0] not found
29 | * j = 2 sum[2] - k = -3, map[-3] not found
30 | * j = 1 sum[1] - k = -2, map[-2] not found
31 | * j = 0 sum[0] - k = -3, map[-3] not found
32 | */
33 | fun maxSubArrayLen(nums: IntArray, k: Int): Int {
34 | //
35 | val map = hashMapOf()
36 | val sum = IntArray(nums.size + 1)
37 | var max = 0
38 | map.put(0, 0)
39 |
40 | // Get the prefix sum, and put them into map
41 | for (i in 1..nums.size) {
42 | sum[i] = sum[i - 1] + nums[i - 1]
43 |
44 | // For the same prefix sum, we always save the min index
45 | if (!map.containsKey(sum[i])) {
46 | map.put(sum[i], i)
47 | }
48 | }
49 |
50 | // find the max length
51 | // so we need to from end to start
52 | // prefix + k = sum[i]
53 | for (j in nums.size downTo 1) {
54 | if (!map.containsKey(sum[j] - k)) continue
55 |
56 | val start = map.getOrDefault(sum[j] - k, 0)
57 | max = Math.max(max, j - start)
58 | }
59 |
60 | return max
61 | }
62 | }
63 |
64 | fun main() {
65 | val res = Med_325_MaxSizeSubArray.maxSubArrayLen(intArrayOf(1, -1, 5, -2, 3), 3)
66 | asserts(res, 4)
67 | val res1 = Med_325_MaxSizeSubArray.maxSubArrayLen(intArrayOf(-2, -1, 2, 1), 1)
68 | asserts(res1, 2)
69 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/array/Med_523_ContinuousSubArraySumK.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.array
2 |
3 | import com.boycoder.utils.asserts
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/21
8 | * @desc: https://leetcode-cn.com/problems/continuous-subarray-sum/
9 | */
10 | object Med_523_ContinuousSubArraySum {
11 | fun checkSubarraySum(nums: IntArray, k: Int): Boolean {
12 | return check1(nums, k)
13 | }
14 |
15 | /**
16 | * prefix sum
17 | *
18 | * similar to [Med_560_SubArrayEqualK.count3]
19 | *
20 | * Ideal from:https://leetcode-cn.com/problems/continuous-subarray-sum/solution/gong-shui-san-xie-tuo-zhan-wei-qiu-fang-1juse/
21 | */
22 | private fun check1(nums: IntArray, k: Int): Boolean {
23 | val sum = IntArray(nums.size + 1)
24 | //
25 | val set = hashSetOf()
26 |
27 | for (i in 1..nums.size) {
28 | sum[i] = sum[i - 1] + nums[i - 1]
29 | }
30 |
31 | for (j in 2..nums.size) {
32 | set.add(sum[j - 2] % k)
33 | if (set.contains(sum[j] % k)) return true
34 | }
35 |
36 | return false
37 | }
38 |
39 | /**
40 | * Brute force
41 | */
42 | private fun check(nums: IntArray, k: Int): Boolean {
43 |
44 | for (start in 0 until nums.size) {
45 | var sum = nums[start]
46 | for (end in (start + 1) until nums.size) {
47 | sum = sum + nums[end]
48 | if (sum % k == 0) {
49 | return true
50 | }
51 | }
52 | }
53 |
54 | return false
55 | }
56 | }
57 |
58 | fun main() {
59 | val res = Med_523_ContinuousSubArraySum.checkSubarraySum(intArrayOf(23,2,4,6,7), 6)
60 | asserts(res, true)
61 | val res1 = Med_523_ContinuousSubArraySum.checkSubarraySum(intArrayOf(23,2,6,4,7), 6)
62 | asserts(res1, true)
63 | val res2 = Med_523_ContinuousSubArraySum.checkSubarraySum(intArrayOf(23,2,6,4,7), 13)
64 | asserts(res2, false)
65 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/array/Med_560_SubArrayEqualK.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.array
2 |
3 | import com.boycoder.utils.asserts
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/21
8 | * @desc: https://leetcode-cn.com/problems/subarray-sum-equals-k/
9 | * Brute force
10 | * Brute force optimize
11 | * Prefix sum
12 | */
13 | object Med_SubArrayEqualK {
14 | fun subarraySum(nums: IntArray, k: Int): Int {
15 | return count3(nums, k)
16 | }
17 |
18 | /**
19 | * ----------sum[i]---------------
20 | * ------prefix[j]-------
21 | * ----k----
22 | * length = i - j
23 | *
24 | * [1,1,1] k = 2
25 | * prefix [0, 1,2,3]
26 | * map [0 to 1, 1 to 1, 2 to 2, 3 to 3]
27 | * end = 3, 3 - k = 1, map[1] = 1, count++
28 | * end = 2, 2 - k = 0, map[0] = 1, count++
29 | * end = 1, 1 - k = -1, map[-1] not found
30 | *
31 | * [-1, -1, 1] k = 0
32 | * prefix [0,-1, -2, -1]
33 | * map [0 to 1, -1 to 2, -2 to 1]
34 | * end = 3, -1 - k = -1, count = 2
35 | *
36 | *
37 | *
38 | * This solution is similar to [Med_325_MaxSizeSubArray.maxSubArrayLen]
39 | */
40 | private fun count3(nums: IntArray, k: Int): Int {
41 | var count = 0
42 | var prefix = 0
43 | val map = hashMapOf()
44 | map.put(0 , 1)
45 |
46 | for (num in nums) {
47 | prefix = prefix + num
48 | if (map.containsKey(prefix - k)) {
49 | count = count + map.getOrDefault(prefix - k, 0)
50 | }
51 |
52 | map.put(prefix, map.getOrDefault(prefix, 0) + 1)
53 | }
54 |
55 | return count
56 | }
57 |
58 | /**
59 | * ----------sum[i]---------------
60 | * ------prefix[j]-------
61 | * ----k----
62 | * loop start end end
63 | * if (prefix[end] - prefix[start]) count++
64 | *
65 | * This solution is similar to [Med_325_MaxSizeSubArray.maxSubArrayLen]
66 | */
67 | private fun count2(nums: IntArray, k: Int): Int {
68 | val prefix = IntArray(nums.size + 1)
69 | var count = 0
70 |
71 | for (i in 1..nums.size) {
72 | prefix[i] = prefix[i - 1] + nums[i - 1]
73 | }
74 |
75 | for (start in 0 until nums.size) {
76 | for (end in (start+1)..nums.size) {
77 | if (prefix[end] - prefix[start] == k) {
78 | count++
79 | }
80 | }
81 | }
82 |
83 | return count
84 | }
85 |
86 |
87 |
88 | /**
89 | * Brute force + optimize
90 | */
91 | private fun count1(nums: IntArray, k: Int): Int {
92 | var count = 0
93 |
94 | for (start in 0 until nums.size) {
95 | var sum = 0
96 | for (end in start until nums.size) {
97 | sum = sum + nums[end]
98 |
99 | if (sum == k) {
100 | count++
101 | }
102 | }
103 | }
104 |
105 | return count
106 | }
107 |
108 | /**
109 | * Brute force
110 | */
111 | private fun count(nums: IntArray, k: Int): Int {
112 | var count = 0
113 |
114 | for (start in 0 until nums.size) {
115 |
116 | for (end in start until nums.size) {
117 | var sum = 0
118 | for (k in start..end) {
119 | sum = sum + nums[k]
120 | }
121 |
122 | if (sum == k) {
123 | count++
124 | }
125 | }
126 | }
127 |
128 | return count
129 | }
130 | }
131 |
132 | fun main() {
133 | val res = Med_SubArrayEqualK.subarraySum(intArrayOf(1, 1, 1), 2)
134 | asserts(res, 2)
135 | val res1 = Med_SubArrayEqualK.subarraySum(intArrayOf(-1, -1, 1), 1)
136 | asserts(res1, 1)
137 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/array/Med_713_SubArrayLessK.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.array
2 |
3 | import com.boycoder.utils.asserts
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/21
8 | * @desc: https://leetcode-cn.com/problems/subarray-product-less-than-k/
9 | * Brutte force
10 | * Two pointer
11 | */
12 | object Med_713_SubArrayLessK {
13 | fun numSubarrayProductLessThanK(nums: IntArray, k: Int): Int {
14 | return count(nums, k)
15 | }
16 |
17 | private fun count(nums: IntArray, k: Int): Int {
18 | if (nums.size == 0) return 0
19 | var left = 0
20 | var product = 1
21 | var count = 0
22 |
23 | for (right in 0 until nums.size) {
24 | product = product * nums[right]
25 |
26 | while (product >= k && left <= right) {
27 | product = product / nums[left]
28 | left++
29 | }
30 |
31 | // find the min left index that [left, right] product less than k
32 | // and in this range, there is (right - left + 1) count
33 | count = count + right - left + 1
34 | }
35 |
36 | return count
37 | }
38 | }
39 |
40 | fun main() {
41 | val res = Med_713_SubArrayLessK.numSubarrayProductLessThanK(intArrayOf(10,5,2,6), 100)
42 | asserts(res, 8)
43 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/array/Med_974_SubArraySumDivisiableK.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.array
2 |
3 | import com.boycoder.utils.asserts
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/21
8 | * @desc: https://leetcode-cn.com/problems/subarray-sums-divisible-by-k/
9 | */
10 | object Med_974_SubArraySumDivisiableK {
11 | fun subarraysDivByK(nums: IntArray, k: Int): Int {
12 | return count1(nums, k)
13 | }
14 |
15 | /**
16 | * Pre sum
17 | *
18 | * ---------------------sum[i]%k=3---------------------------
19 | * ----------sum[j]%k=3-----------
20 | * ---------sum[i,j]%k=0------
21 | *
22 | *
23 | * similar to [Med_523_ContinuousSubArraySumK]
24 | */
25 | private fun count1(nums: IntArray, k: Int): Int {
26 | var presum = 0
27 | var count = 0
28 | val map = hashMapOf()
29 | map[0] = 1
30 |
31 | for (i in nums) {
32 | presum = presum + i
33 | // presum maybe negative
34 | val key = (presum % k + k) % k
35 | if (map.containsKey(key)) {
36 | count = count + map.getOrDefault(key, 0)
37 | }
38 | map[key] = map.getOrDefault(key, 0) + 1
39 | }
40 |
41 | return count
42 | }
43 |
44 | /**
45 | * Brute force
46 | */
47 | private fun count(nums: IntArray, k: Int): Int {
48 | var count = 0
49 |
50 | for (start in 0 until nums.size) {
51 | var sum = 0
52 | for (end in start until nums.size) {
53 | sum = sum + nums[end]
54 |
55 | if (sum % k == 0) {
56 | count++
57 | }
58 | }
59 | }
60 |
61 | return count
62 | }
63 | }
64 |
65 | fun main() {
66 | val res = Med_974_SubArraySumDivisiableK.subarraysDivByK(intArrayOf(4,5,0,-2,-3,1), 5)
67 | asserts(res, 7)
68 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/backtrack/Hard_51_NQueens.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.backtrack
2 |
3 | /**
4 | * @Author: zhutao
5 | * @datetime: 2021/6/22
6 | * @desc:
7 | *
8 | * Ideal
9 | * For a n*n chessboard, we need to take n step.
10 | * And for every step, we can choose i = [0, n); j = [0, n)
11 | *
12 | * We use loop go through the col, and recursion go through the row,
13 | * and for every step, we check validation.
14 | */
15 | object Hard_51_NQueens {
16 | private val list: MutableList> = mutableListOf()
17 | private val path: MutableList> = mutableListOf()
18 | private var n = 0
19 |
20 | fun solveNQueens(n: Int): List> {
21 | this.n = n
22 | backtrack(0)
23 | return list
24 | }
25 |
26 | private fun backtrack(row: Int) {
27 | if (path.size == n) {
28 | saveResult()
29 | return
30 | }
31 |
32 | for (col in 0 until n) {
33 | if (!isValid(row, col)) {
34 | continue
35 | }
36 |
37 | path.add(Pair(row, col))
38 | backtrack(row + 1)
39 | path.removeAt(path.size - 1)
40 | }
41 |
42 | }
43 |
44 | private fun saveResult() {
45 | path.sortBy{ it.first }
46 | val tempList = mutableListOf()
47 | for (i in 0 until n) {
48 | val pair = path[i]
49 | var temp = StringBuilder()
50 | for (j in 0 until n) {
51 | if (j == pair.second) {
52 | temp.append("Q")
53 | } else {
54 | temp.append(".")
55 | }
56 | }
57 | tempList.add(temp.toString())
58 | }
59 |
60 | list.add(tempList)
61 | }
62 |
63 | private fun isValid(row: Int, col: Int): Boolean {
64 | for (pair in path) {
65 | if (!isPairValid(pair, row, col)) {
66 | return false
67 | }
68 | }
69 |
70 | return true
71 | }
72 |
73 | private fun isPairValid(pair: Pair, row: Int, col: Int): Boolean {
74 | if (pair.first == row || pair.second == col) {
75 | return false
76 | }
77 |
78 | val x = Math.abs(pair.second - col)
79 | val y = Math.abs(pair.first - row)
80 | if (x == y) {
81 | return false
82 | }
83 |
84 | return true
85 | }
86 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/backtrack/Med_077_Combinations.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.backtrack
2 |
3 | /**
4 | * @Author: zhutao
5 | * @datetime: 2021/6/4
6 | * @desc:
7 | *
8 | Ideal
9 |
10 | For 1...n K combination, we pick one for loop, one for recursion
11 | If we use n to loop, then we recur until we collet k elements
12 | 1..n is not very good for recursion
13 |
14 | eg: n = 3, k = 2
15 |
16 | [1,2,3]
17 | 1/ 2| \3
18 | [2,3] [3] []
19 | 2/ \3 |3
20 | (1,2) (1,3) (2,3)
21 |
22 |
23 | */
24 | object Med_077_Combinations {
25 | val list: MutableList> = mutableListOf()
26 | val path: MutableList = mutableListOf()
27 | var n = 0
28 |
29 | fun combine(n: Int, k: Int): List> {
30 | this.n = n
31 | dfs(path, 1, k)
32 | return list
33 | }
34 |
35 | // Another way for combination
36 | private fun dfs(path: MutableList, start: Int, k: Int) {
37 | if (path.size == k) {
38 | list.add(path)
39 | return
40 | }
41 |
42 | if (path.size > k) {
43 | return
44 | }
45 |
46 | if (start > n) {
47 | return
48 | }
49 |
50 | dfs(path.toMutableList().also{ it.add(start) }, start + 1, k)
51 | dfs(path.toMutableList(), start + 1, k)
52 | }
53 |
54 | // pruming got better performance
55 | private fun doCombinePruming(n: Int, start: Int, k: Int) {
56 |
57 | if (path.size == k) {
58 | // careful toMutableList()
59 | list.add(path.toMutableList())
60 | return
61 | }
62 |
63 | // conner case: k = 2, start = 2, n = 3, path.size = 0
64 | if ((k - path.size - 1) > (n - start)) return
65 |
66 | // careful start..n
67 | // every time start, we can avoid duplication
68 | for (i in start..n) {
69 | // conner case: k = 2, i = 2, n = 3, path.size = 0
70 | if ((k - path.size - 1) > (n - i)) continue
71 |
72 | path.add(i)
73 | doCombinePruming(n, i + 1, k)
74 | path.remove(i)
75 | }
76 | }
77 |
78 | private fun doCombine(n: Int, start: Int, k: Int) {
79 |
80 | if (path.size == k) {
81 | // careful toMutableList()
82 | list.add(path.toMutableList())
83 | return
84 | }
85 |
86 | // careful start..n
87 | // every time start, we can avoid duplication
88 | for (i in start..n) {
89 | path.add(i)
90 | doCombine(n, i + 1, k)
91 | path.remove(i)
92 | }
93 | }
94 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/backtrack/Med_131_PalindromePartition.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.backtrack
2 |
3 | /**
4 | * @Author: zhutao
5 | * @datetime: 2021/6/22
6 | * @desc:
7 | *
8 | * Ideal
9 | * For the given string,
10 | * we check if it can be split into several substring,
11 | * that every substring is palindrome.
12 | * We need a loop to help us split at index.
13 | * For every index, we decide how many chars we split,
14 | * and then save the split result and pass the remain into the recursion.
15 | *
16 | * eg: aab down recursion
17 | * /a |aa \ |
18 | * ab b [] |
19 | * a/\ | when start index = size - 1
20 | * b [] [aa, b]
21 | * |
22 | * [a, a, b]
23 | *
24 | * ------------->
25 | * Loop to decide how many char to split
26 | *
27 | */
28 | object Med_131_PalindromePartition {
29 | private val list: MutableList> = mutableListOf()
30 | private val path: MutableList = mutableListOf()
31 |
32 | fun partition(s: String): List> {
33 | part(s.toCharArray(), 0)
34 | return list
35 | }
36 |
37 | private fun part(array: CharArray, start: Int) {
38 | if (start == array.size) {
39 | list.add(path.toMutableList())
40 | return
41 | }
42 |
43 | // pruming
44 | if (start > array.size) {
45 | return
46 | }
47 |
48 | for (i in start until array.size) { // [start, size - 1]
49 | if (!isPalindrome(array, start, i)) {
50 | continue
51 | }
52 | path.add(array.slice(start..i).joinToString(""))
53 | part(array, i + 1)
54 | path.removeAt(path.size - 1)
55 | }
56 | }
57 |
58 | private fun isPalindrome(array: CharArray, left: Int, right: Int): Boolean {
59 | var left = left
60 | var right = right
61 |
62 | while (left < right) {
63 | if (array[left] != array[right]) {
64 | return false
65 | }
66 | left++
67 | right--
68 | }
69 |
70 | return true
71 | }
72 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/backtrack/Med_17_LetterCombinationPhoneNum.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.backtrack
2 |
3 | /**
4 | * @Author: zhutao
5 | * @datetime: 2021/6/22
6 | * @desc:
7 | */
8 | object Med_17_LetterCombinationPhoneNum {
9 | private val list: MutableList = mutableListOf()
10 | private val path: MutableList = mutableListOf()
11 |
12 | fun letterCombinations(digits: String): List {
13 | if (digits.isBlank()) return list
14 | combine(digits.toCharArray(), 0)
15 | return list
16 | }
17 |
18 | private fun combine(digits: CharArray, index: Int) {
19 | if (path.size == digits.size) {
20 | list.add(path.joinToString(""))
21 | return
22 | }
23 |
24 | if (index >= digits.size) return
25 |
26 | val array = getChars(digits[index])
27 |
28 | for (char in array) {
29 | path.add(char)
30 | combine(digits, index + 1)
31 | // careful
32 | // for test case: "999"
33 | // path.remove(char) wont pass
34 | // so for this case we need remove last
35 | path.removeAt(path.size - 1)
36 | }
37 | }
38 |
39 | private inline fun getChars(num: Char): CharArray {
40 | return when (num) {
41 | '2' -> charArrayOf('a', 'b', 'c')
42 | '3' -> charArrayOf('d', 'e', 'f')
43 | '4' -> charArrayOf('g', 'h', 'i')
44 | '5' -> charArrayOf('j', 'k', 'l')
45 | '6' -> charArrayOf('m', 'n', 'o')
46 | '7' -> charArrayOf('p', 'q', 'r', 's')
47 | '8' -> charArrayOf('t', 'u', 'v')
48 | '9' -> charArrayOf('w', 'x', 'y', 'z')
49 | else -> return charArrayOf()
50 | }
51 | }
52 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/backtrack/Med_216_CombinationSumIII.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.backtrack
2 |
3 | /**
4 | * @Author: zhutao
5 | * @datetime: 2021/6/22
6 | * @desc:
7 | */
8 | object Med_216_CombinationSumIII {
9 | private val list: MutableList> = mutableListOf()
10 | private val path: MutableList = mutableListOf()
11 |
12 | fun combinationSum3(k: Int, n: Int): List> {
13 | combine(k, n, n, 1)
14 | return list
15 | }
16 |
17 | // with pruming
18 | private fun combine(k: Int, n: Int, remain: Int, start: Int) {
19 | if (remain < 0) return
20 |
21 | if (path.size == k) {
22 | if (remain == 0) {
23 | list.add(path.toMutableList())
24 | }
25 |
26 | return
27 | }
28 |
29 | // conner case: start > remain
30 | if (start > remain) return
31 |
32 | // conner case: k = 3, start = 8, path.size = 1
33 | if ((k - path.size - 1) > 9 - start) return
34 |
35 | for (i in start..9) {
36 | path.add(i)
37 | combine(k, n, remain - i, i + 1)
38 | path.removeAt(path.size - 1)
39 | }
40 | }
41 |
42 | private fun combineNoPruming(k: Int, n: Int, remain: Int, start: Int) {
43 | if (remain < 0) return
44 |
45 | if (path.size == k) {
46 | if (remain == 0) {
47 | list.add(path.toMutableList())
48 | }
49 |
50 | return
51 | }
52 |
53 | for (i in start..9) {
54 | path.add(i)
55 | combine(k, n, remain - i, i + 1)
56 | path.removeAt(path.size - 1)
57 | }
58 | }
59 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/backtrack/Med_332_ReconstructItinerary.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.backtrack
2 |
3 | import java.util.*
4 | import kotlin.collections.HashMap
5 |
6 | /**
7 | * @Author: zhutao
8 | * @datetime: 2021/6/22
9 | * @desc:
10 | *
11 | * Ideal
12 | * We take airport as vertex and ticket as edge.
13 | * Map>
14 | * it means for this airport we can go to destination count times.
15 | * We start from JFK,
16 | * and find a way that all the list.size = tickets.size + 1,
17 | * it means we used all the tickets.
18 | * This is a normal dfs
19 | */
20 | object Med_332_ReconstructItinerary {
21 | // sorted by key
22 | private val graph: HashMap> = hashMapOf()
23 | private val path: MutableList = mutableListOf()
24 | private var count = 0
25 |
26 | fun findItinerary(tickets: List>): List {
27 | // pre process
28 | count = tickets.size
29 | for (ticket in tickets) {
30 | val start = ticket[0]
31 | val destination = ticket[1]
32 |
33 | // careful: Kotlin sortedMapOf() means TreeMap
34 | val map = graph[start]?: sortedMapOf()
35 | map.put(destination, map.getOrDefault(destination, 0) + 1)
36 |
37 | graph[start] = map
38 | }
39 |
40 | // start from JFK
41 | path.add("JFK")
42 | backtrack("JFK")
43 | return path
44 | }
45 |
46 | private fun backtrack(start: String): Boolean {
47 | if (path.size == count + 1) {
48 | return true
49 | }
50 |
51 | // this is a tree map
52 | val destMap = graph[start]?:return false
53 |
54 | for (entry in destMap.entries) {
55 | if (entry.value <= 0) {
56 | continue
57 | }
58 | val value = entry.value
59 | val key = entry.key
60 |
61 | path.add(entry.key)
62 | destMap.put(key, value - 1)
63 | if (backtrack(entry.key)) {
64 | return true
65 | }
66 | path.removeAt(path.size - 1)
67 | destMap.put(key, value)
68 | }
69 |
70 | return false
71 | }
72 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/backtrack/Med_39_CombinationSum.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.backtrack
2 |
3 | /**
4 | * @Author: zhutao
5 | * @datetime: 2021/6/22
6 | * @desc: https://leetcode-cn.com/problems/combination-sum/
7 | */
8 | object Med_39_CombinationSum {
9 | private val list: MutableList> = mutableListOf()
10 | private val path: MutableList = mutableListOf()
11 | private var sum: Int = 0
12 |
13 | fun combinationSum(candidates: IntArray, target: Int): List> {
14 | combine(candidates, target, 0)
15 | return list
16 | }
17 |
18 | private fun combine(nums: IntArray, target: Int, start: Int) {
19 | if (sum > target) return
20 |
21 | if (sum == target) {
22 | // careful toMutableList
23 | list.add(path.toMutableList())
24 | return
25 | }
26 |
27 | for (i in start until nums.size) {
28 | path.add(nums[i])
29 | sum = sum + nums[i]
30 | // We can pick the same element many times, so dont use i+1
31 | // By using i, every recursion can pick the same value
32 | combine(nums, target, i)
33 | sum = sum - nums[i]
34 | path.removeAt(path.size - 1)
35 | }
36 | }
37 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/backtrack/Med_40_CombinationSumII.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.backtrack
2 |
3 | /**
4 | * @Author: zhutao
5 | * @datetime: 2021/6/22
6 | * @desc: https://leetcode-cn.com/problems/combination-sum-ii/
7 | */
8 | object Med_40_CombinationSumII {
9 | private val list: MutableList> = mutableListOf()
10 | private val path: MutableList = mutableListOf()
11 | private var sum = 0
12 |
13 | fun combinationSum2(candidates: IntArray, target: Int): List> {
14 | /**
15 | Though we can use a set in a level to avoid the same element been pick more than one time.
16 | But we still need to sort the array to avoid duplication
17 | EG: 1,2,7,1
18 | / \
19 | 2,7,1 1
20 | \ (7, 1)
21 | (1, 7)
22 |
23 | EG: 1,1,2,7
24 | / \
25 | 2,7,1 (NO)
26 | \
27 | (1, 7)
28 | */
29 | candidates.sort()
30 | combine(candidates, target, 0)
31 | return list
32 | }
33 |
34 | /**
35 | * So, to avoid duplication,
36 | * we can use sort and nums[i] == nums[i - 1] to check
37 | */
38 | private fun combine(nums: IntArray, target: Int, start: Int) {
39 | if (sum > target) return
40 |
41 | if (sum == target) {
42 | list.add(path.toMutableList())
43 | return
44 | }
45 |
46 | for (i in start until nums.size) {
47 | if (i > start && nums[i] == nums[i - 1]) continue
48 |
49 | path.add(nums[i])
50 | sum = sum + nums[i]
51 | // We dont want to pick the same element more than once
52 | // So in the next level of recursion, the start index is i + 1
53 | // then it never repeat the same index for the single combination
54 | combine(nums, target, i + 1)
55 | sum = sum - nums[i]
56 | path.removeAt(path.size - 1)
57 | }
58 | }
59 |
60 | private fun combine1(nums: IntArray, target: Int, start: Int) {
61 | if (sum > target) return
62 |
63 | if (sum == target) {
64 | list.add(path.toMutableList())
65 | return
66 | }
67 |
68 | val set: HashSet = hashSetOf()
69 | for (i in start until nums.size) {
70 | if (set.contains(nums[i])) continue
71 | set.add(nums[i])
72 |
73 | path.add(nums[i])
74 | sum = sum + nums[i]
75 | // We dont want to pick the same element more than once
76 | // So in the next level of recursion, the start index is i + 1
77 | // then it never repeat the same index for the single combination
78 | combine(nums, target, i + 1)
79 | sum = sum - nums[i]
80 | path.removeAt(path.size - 1)
81 | }
82 | }
83 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/backtrack/Med_46_Permutations.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.backtrack
2 |
3 | /**
4 | * @Author: zhutao
5 | * @datetime: 2021/6/22
6 | * @desc:
7 | *
8 | * Ideal
9 | * Use recursion and backtrack to solve permutations problem
10 | *
11 | * Because we need permutations, so we can reuse the same array in every level. But the same element can not duplicate in the same path, so we need to check the element going to visit, if it in the path already.
12 | *
13 | * The difference between combination and permutation is :
14 | * 1. No start index passed
15 | * 2. Always loop from 0
16 | * 3. No duplicate for the path elements
17 | */
18 | object Med_46_Permutations {
19 | private val list: MutableList> = mutableListOf()
20 | private val path: MutableList = mutableListOf()
21 |
22 | fun permute(nums: IntArray): List> {
23 | backtrack(nums)
24 | return list
25 | }
26 |
27 | private fun backtrack(array: IntArray) {
28 | if (path.size == array.size) {
29 | list.add(path.toList())
30 | }
31 |
32 | for (i in 0 until array.size) {
33 | // we can do this only if the elements in array wont duplicate (are distinct)
34 | if (path.contains(array[i])) {
35 | continue
36 | }
37 | path.add(array[i])
38 | backtrack(array)
39 | path.removeAt(path.size - 1)
40 | }
41 | }
42 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/backtrack/Med_47_PermutationsII.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.backtrack
2 |
3 | /**
4 | * @Author: zhutao
5 | * @datetime: 2021/6/22
6 | * @desc:
7 | *
8 | * Ideal
9 | * This is a little bit like https://leetcode-cn.com/problems/permutations/
10 | * For this case,
11 | * we can sort the array and make sure in the same loop we dont visit the same element.
12 | * And because the elements in array can be duplicate,
13 | * so we can not use path.contains(value) to check,
14 | * we need to record the index, not the value, for the path.
15 | */
16 | object Med_47_PermutationsII {
17 | private val list: MutableList> = mutableListOf()
18 | private val path: MutableList = mutableListOf()
19 | private val used = BooleanArray(21)
20 |
21 | fun permuteUnique(nums: IntArray): List> {
22 | nums.sort()
23 | backtrack(nums)
24 | return list
25 | }
26 |
27 | private fun backtrack(array: IntArray) {
28 | if (path.size == array.size) {
29 | list.add(path.toList())
30 | return
31 | }
32 |
33 | val set = hashSetOf()
34 |
35 | for (i in 0 until array.size) {
36 | // avoid duplication for the same result
37 | if (used[i + 10]) {
38 | continue
39 | }
40 |
41 | // for the same level loop we avoid duplicate value
42 | if (set.contains(array[i])) {
43 | continue
44 | }
45 | set.add(array[i])
46 |
47 | used[i + 10] = true
48 | path.add(array[i])
49 | backtrack(array)
50 | used[i + 10] = false
51 | path.removeAt(path.size - 1)
52 | }
53 | }
54 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/backtrack/Med_491_IncreasingSubSequences.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.backtrack
2 |
3 | /**
4 | * @Author: zhutao
5 | * @datetime: 2021/6/22
6 | * @desc:
7 | */
8 | object Med_491_IncreasingSubSequences {
9 | private val list: MutableList> = mutableListOf()
10 | private val path: MutableList = mutableListOf()
11 |
12 | fun findSubsequences(nums: IntArray): List> {
13 | backtrack(nums, 0)
14 | return list
15 | }
16 |
17 | private fun backtrack(array: IntArray, start: Int) {
18 | if (path.size > 1) {
19 | list.add(path.toList())
20 | }
21 |
22 | if (start >= array.size) {
23 | return
24 | }
25 |
26 | val used = BooleanArray(210)
27 | for (i in start until array.size) {
28 | if (path.size > 0 && array[i] < path[path.size - 1]) {
29 | continue
30 | }
31 |
32 | if (used[array[i] + 100]) {
33 | continue
34 | }
35 |
36 | used[array[i] + 100] = true
37 |
38 | path.add(array[i])
39 | backtrack(array, i + 1)
40 | path.removeAt(path.size - 1)
41 | }
42 | }
43 |
44 | private fun find(array: IntArray, start: Int) {
45 | if (path.size > 1) {
46 | list.add(path.toList())
47 | }
48 |
49 | if (start >= array.size) {
50 | return
51 | }
52 |
53 | val set = hashSetOf()
54 | for (i in start until array.size) {
55 | if (!isValid(set, array[i])) {
56 | continue
57 | }
58 |
59 | set.add(array[i])
60 | path.add(array[i])
61 | find(array, i + 1)
62 | path.removeAt(path.size - 1)
63 | }
64 | }
65 |
66 | // current elment is smaller than path end element
67 | // current element has been visited
68 | private fun isValid(set: HashSet, num: Int): Boolean {
69 | if (path.size > 0 &&
70 | num < path[path.size - 1]) {
71 | // not increasing
72 | return false
73 | }
74 |
75 | if (set.contains(num)) {
76 | return false
77 | }
78 |
79 | return true
80 | }
81 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/backtrack/Med_78_SubSet.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.backtrack
2 |
3 | /**
4 | * @Author: zhutao
5 | * @datetime: 2021/6/22
6 | * @desc:
7 | *
8 | * Ideal
9 | * For the sub set of a set. When we trying to find the combination, all the node of this tree(state of path), are the no-duplicate subset
10 | *
11 | * eg: n = 3
12 | *
13 | * [1,2,3]
14 | * 1/ 2| \3
15 | * [2,3] [3] []
16 | * 2/ \3 |3
17 | * [3] [] []
18 | * 3/
19 | * []
20 | *
21 | */
22 | object Med_78_SubSet {
23 | private val list: MutableList> = mutableListOf()
24 | private val path: MutableList = mutableListOf()
25 |
26 | fun subsets(nums: IntArray): List> {
27 | sub(nums, 0)
28 | return list
29 | }
30 |
31 | private fun sub(nums: IntArray, start: Int) {
32 |
33 | list.add(path.toList())
34 |
35 | if (start >= nums.size) {
36 | return
37 | }
38 |
39 | for (i in start until nums.size) {
40 | path.add(nums[i])
41 | sub(nums, i + 1)
42 | path.removeAt(path.size - 1)
43 | }
44 | }
45 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/backtrack/Med_90_SubSetII.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.backtrack
2 |
3 | /**
4 | * @Author: zhutao
5 | * @datetime: 2021/6/22
6 | * @desc:
7 | */
8 | object Med_90_SubSetII {
9 | private val list: MutableList> = mutableListOf()
10 | private val path: MutableList = mutableListOf()
11 |
12 | fun subsetsWithDup(nums: IntArray): List> {
13 | nums.sort()
14 | sub(nums, 0)
15 | return list
16 | }
17 |
18 | // using sorted array and num[i] == nums[i - 1] to check
19 | private fun sub(nums: IntArray, start: Int) {
20 | list.add(path.toList())
21 |
22 | if (path.size >= nums.size) {
23 | return
24 | }
25 |
26 | for (i in start until nums.size) {
27 | if (i > start && nums[i] == nums[i - 1]) {
28 | continue
29 | }
30 |
31 | path.add(nums[i])
32 | sub(nums, i + 1)
33 | path.removeAt(path.size - 1)
34 | }
35 | }
36 |
37 | private fun sub1(nums: IntArray, start: Int) {
38 | list.add(path.toList())
39 |
40 | if (path.size >= nums.size) {
41 | return
42 | }
43 |
44 | val set = hashSetOf()
45 | for (i in start until nums.size) {
46 | if (set.contains(nums[i])) {
47 | continue
48 | }
49 | set.add(nums[i])
50 |
51 | path.add(nums[i])
52 | sub(nums, i + 1)
53 | path.removeAt(path.size - 1)
54 | }
55 | }
56 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/backtrack/Med_93_RestoreIPAddress.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.backtrack
2 |
3 | /**
4 | * @Author: zhutao
5 | * @datetime: 2021/6/22
6 | * @desc:
7 | *
8 | * Ideal
9 | * This problem is a little bit like palindrome-partitioning
10 | * Back tracking can be use in partitioning
11 | *
12 | * For the loop, we decide how many char to split,
13 | * from 1 to 3, check valide, then we save the path,
14 | * and pass the rest of string into the recursion i + 1.
15 | *
16 | * For the recursion, we check path.size == 4 && start == string.size
17 | * "25525511135"
18 | *
19 | */
20 | object Med_93_RestoreIPAddress {
21 | private val list: MutableList = mutableListOf()
22 | private val path: MutableList = mutableListOf()
23 |
24 | fun restoreIpAddresses(s: String): List {
25 | split(s, 0)
26 | return list
27 | }
28 |
29 | private fun split(s: String, start: Int) {
30 | if (path.size == 4) {
31 | if (start == s.length) {
32 | // all string are used
33 | list.add(path.joinToString("."))
34 | }
35 | return
36 | }
37 |
38 | // pruming
39 | // if there is too many num left
40 | // such as:
41 | // s.length == 13
42 | if ((4 - path.size) * 3 < (s.length - start)) {
43 | return
44 | }
45 |
46 | // s = "25525511135" s.length = 11
47 | // start = 9
48 | val end = Math.min(start + 3, s.length)
49 | for (i in start until end) {
50 | val temp = s.slice(start..i)
51 | if (!isValid(temp)) continue
52 |
53 | path.add(temp)
54 | split(s, i + 1)
55 | path.removeAt(path.size - 1)
56 | }
57 | }
58 |
59 | private fun isValid(s: String): Boolean {
60 | if (s.startsWith("0")) {
61 | // only zero can start with 0
62 | return s.length == 1
63 | } else {
64 | val num = s.toInt()
65 | return num in 0..255
66 | }
67 | }
68 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/bst/Easy_108_ArrayToBST.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.bst
2 |
3 | import com.boycoder.basis.datastructure.TreeNode
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/22
8 | * @desc:
9 | */
10 | object Easy_108_ArrayToBST {
11 | fun sortedArrayToBST(nums: IntArray): TreeNode? {
12 | return build(nums, 0, nums.size - 1)
13 | }
14 |
15 | private fun build(nums: IntArray, left: Int, right: Int): TreeNode? {
16 | if (left > right) return null
17 |
18 | val mid = left + ((right - left) / 2)
19 |
20 | val root = TreeNode(nums[mid])
21 | root.left = build(nums, left, mid - 1)
22 | root.right = build(nums, mid + 1, right)
23 |
24 | return root
25 | }
26 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/bst/Easy_235_LowestCommonAncestorBST.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.bst
2 |
3 | import com.boycoder.basis.datastructure.TreeNode
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/22
8 | * @desc:
9 | */
10 | object Easy_235_LowestCommonAncestorBST {
11 | fun lowestCommonAncestor(root: TreeNode?, p: TreeNode?, q: TreeNode?): TreeNode? {
12 | if (root == null || p == null || q == null) return null
13 | return find(root, p, q)
14 | }
15 |
16 | private fun find(root: TreeNode?, p: TreeNode, q: TreeNode): TreeNode? {
17 | if (root == null) return null
18 |
19 | var node: TreeNode? = root
20 | while (node != null) {
21 | if (node.value > p.value && node.value > q.value) {
22 | node = node.left
23 | } else if (node.value < p.value && node.value < q.value) {
24 | node = node.right
25 | } else {
26 | return node
27 | }
28 | }
29 |
30 | return null
31 | }
32 |
33 | // recursion
34 | private fun find1(root: TreeNode?, p: TreeNode, q: TreeNode): TreeNode? {
35 | if (root == null) return null
36 |
37 | if (root.value > p.value && root.value > q.value) {
38 | return find(root.left, p, q)
39 | } else if (root.value < p.value && root.value < q.value) {
40 | return find(root.right, p, q)
41 | } else {
42 | return root
43 | }
44 | }
45 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/bst/Easy_501_ModeInBST.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.bst
2 |
3 | import com.boycoder.basis.datastructure.TreeNode
4 | import java.util.*
5 | import kotlin.collections.ArrayList
6 |
7 | /**
8 | * @Author: zhutao
9 | * @datetime: 2021/6/22
10 | * @desc:
11 | */
12 | object Easy_501_ModeInBST {
13 | var pre: TreeNode? = null
14 | var max: Int = 0
15 | var count: Int = 0
16 | val list = ArrayList()
17 |
18 | fun findMode(root: TreeNode?): IntArray {
19 | find1(root)
20 | return list.toIntArray()
21 | }
22 |
23 | /**
24 | * loop + stack
25 | *
26 | * in order traversal
27 | */
28 | private fun find1(root: TreeNode?) {
29 | if (root == null) return
30 |
31 | val stk = LinkedList()
32 | stk.add(root)
33 |
34 | while (!stk.isEmpty()) {
35 | val node = stk.getLast()
36 |
37 | if (node != null) {
38 | stk.removeLast()
39 |
40 | // right
41 | if (node.right != null) stk.addLast(node.right)
42 | // root
43 | stk.addLast(node)
44 | stk.addLast(null)
45 | // left
46 | if (node.left != null) stk.addLast(node.left)
47 | } else {
48 | // remove null
49 | stk.removeLast()
50 |
51 | val temp = stk.removeLast()?:return
52 | if (pre == null) {
53 | count = 1
54 | } else if (pre?.value == temp.value){
55 | count++
56 | } else {
57 | count = 1
58 | }
59 |
60 | if (count == max) {
61 | list.add(temp.value)
62 | }
63 |
64 | if (count > max) {
65 | list.clear()
66 | list.add(temp.value)
67 | }
68 |
69 | max = Math.max(max, count)
70 | pre = temp
71 | }
72 | }
73 | }
74 |
75 | // recursion with pointer
76 | private fun find(root: TreeNode?) {
77 | if (root == null) return
78 |
79 | find(root.left)
80 |
81 | if (pre == null) {
82 | count = 1
83 | list.add(root.value)
84 | } else if (pre!!.value == root.value) {
85 | count++
86 | } else {
87 | count = 1
88 | }
89 |
90 | if (count == max) {
91 | list.add(root.value)
92 | }
93 |
94 | if (count > max) {
95 | list.clear()
96 |
97 | list.add(root.value)
98 | }
99 |
100 | max = Math.max(count, max)
101 | pre = root
102 |
103 | find(root.right)
104 | }
105 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/bst/Easy_530_AbsDifferenceInBST.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.bst
2 |
3 | import com.boycoder.basis.datastructure.TreeNode
4 | import java.util.*
5 |
6 | /**
7 | * @Author: zhutao
8 | * @datetime: 2021/6/22
9 | * @desc:
10 | */
11 | object Easy_530_AbsDifferenceInBST {
12 |
13 | // we can store the value only to get more performance
14 | private var pre:TreeNode? = null
15 | private var min = Int.MAX_VALUE
16 |
17 | fun getMinimumDifference(root: TreeNode?): Int {
18 | getMin(root)
19 | return min
20 | }
21 |
22 | private fun getMin(root: TreeNode?) {
23 | if (root == null) return
24 |
25 | val stk = LinkedList()
26 | stk.addLast(root)
27 | var node: TreeNode? = null
28 |
29 | while (!stk.isEmpty()) {
30 | node = stk.getLast() // peek
31 |
32 | node?.let {
33 | stk.removeLast()
34 |
35 | if (it.right != null) stk.addLast(it.right)
36 |
37 | stk.addLast(it)
38 | stk.addLast(null)
39 |
40 | if (it.left != null) stk.addLast(it.left)
41 | }?: run {
42 | stk.removeLast() // remove null
43 | val cur = stk.removeLast()?: return // element itself
44 |
45 | pre?.let {
46 | min = Math.min(min, cur.value - it.value)
47 | }
48 | pre = cur
49 | }
50 | }
51 | }
52 |
53 | private fun getMin1(root: TreeNode?) {
54 | if (root == null) return
55 |
56 | getMin(root.left)
57 |
58 | pre?.let {
59 | // cur is always larger than pre
60 | min = Math.min(min, root.value - it.value)
61 | }
62 | pre = root
63 |
64 | getMin(root.right)
65 | }
66 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/bst/Easy_700_SearchInBST.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.bst
2 |
3 | import com.boycoder.basis.datastructure.TreeNode
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/22
8 | * @desc:
9 | */
10 | object Easy_700_SearchInBST {
11 | fun searchBST(root: TreeNode?, target: Int): TreeNode? {
12 | if (root == null) return null
13 | if (root.value == target) return root
14 | if (root.value > target) return searchBST(root.left, target)
15 | if (root.value < target) return searchBST(root.right, target)
16 |
17 | return null
18 | }
19 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/bst/Med_450_DeleteInBST.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.bst
2 |
3 | import com.boycoder.basis.datastructure.TreeNode
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/22
8 | * @desc:
9 | */
10 | object Med_450_DeleteInBST {
11 | fun deleteNode(root: TreeNode?, key: Int): TreeNode? {
12 | return delete(root, key)
13 | }
14 |
15 | private fun delete(root: TreeNode?, key: Int): TreeNode? {
16 | if (root == null) return null
17 |
18 | if (root.value == key) {
19 | if (root.left == null && root.right == null) {
20 | // return null means delete
21 | return null
22 | } else if (root.left == null && root.right != null) {
23 | return root.right
24 | } else if (root.left != null && root.right == null) {
25 | return root.left
26 | } else {
27 | // left != null right != null
28 | var node = root.right!!
29 | // find successor
30 | while (node.left != null) {
31 | node = node.left!!
32 | }
33 | node.left = root.left
34 | root.left = null
35 | return root.right
36 | }
37 | } else if (root.value > key) {
38 | root.left = delete(root.left, key)
39 | } else if (root.value < key) {
40 | root.right = delete(root.right, key)
41 | }
42 |
43 | return root
44 | }
45 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/bst/Med_538_BSTToGreaterTree.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.bst
2 |
3 | import com.boycoder.basis.datastructure.TreeNode
4 | import java.util.*
5 |
6 | /**
7 | * @Author: zhutao
8 | * @datetime: 2021/6/22
9 | * @desc:
10 | */
11 | object Med_538_BSTToGreaterTree {
12 | var pre: TreeNode? = null
13 | fun convertBST(root: TreeNode?): TreeNode? {
14 | return conver(root)
15 | }
16 |
17 | // loop, treat this tree as normal binary tree
18 | private fun conver(root: TreeNode?): TreeNode? {
19 | if (root == null) return null
20 |
21 | val stk = LinkedList()
22 | stk.addLast(root)
23 |
24 | while (!stk.isEmpty()) {
25 | val node = stk.getLast()
26 |
27 | if (node != null) {
28 | // reversed inorder traversal
29 | stk.removeLast()
30 |
31 | if (node.left != null) stk.addLast(node.left)
32 |
33 | stk.addLast(node)
34 | stk.addLast(null)
35 |
36 | if (node.right != null) stk.addLast(node.right)
37 | } else {
38 | stk.removeLast() // remove null
39 |
40 | // traversal element
41 | stk.removeLast()?.let {
42 | if (pre != null) {
43 | it.value = pre!!.value + it.value
44 | }
45 | pre = it
46 | }
47 | }
48 | }
49 |
50 | return root
51 | }
52 |
53 |
54 | // recursion
55 | private fun conver1(root: TreeNode?): TreeNode? {
56 | if (root == null) return root
57 |
58 | conver(root.right)
59 | if (pre != null) {
60 | root.value = pre!!.value + root.value
61 | }
62 | pre = root
63 | conver(root.left)
64 |
65 | return root
66 | }
67 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/bst/Med_669_TrimBST.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.bst
2 |
3 | import com.boycoder.basis.datastructure.TreeNode
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/22
8 | * @desc:
9 | */
10 | object Med_669_TrimBST {
11 | fun trimBST(root: TreeNode?, low: Int, high: Int): TreeNode? {
12 | return trim(root, low, high)
13 | }
14 |
15 | private fun trim(root: TreeNode?, low: Int, high: Int): TreeNode? {
16 | var node = root
17 | if (node == null) return null
18 |
19 | if (node.value < low && node.value < high) {
20 | // drop the left side
21 | node = node.right
22 | node = trim(node, low, high)
23 | } else if (node.value > high && node.value > low) {
24 | // drop the right side
25 | node = node.left
26 | node = trim(node, low, high)
27 | } else {
28 | // node is fine
29 | // but we need to check node.left and node right
30 | node.left = trim(node.left, low, high)
31 | node.right = trim(node.right, low, high)
32 | }
33 |
34 | return node
35 | }
36 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/bst/Med_701_InsertIntoBST.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.bst
2 |
3 | import com.boycoder.basis.datastructure.TreeNode
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/22
8 | * @desc:
9 | */
10 | object Med_701_InsertIntoBST {
11 | fun insertIntoBST(root: TreeNode?, target: Int): TreeNode? {
12 | return insert(root, target)
13 | }
14 |
15 | private fun insert(root: TreeNode?, target: Int): TreeNode? {
16 | if (root == null) return TreeNode(target)
17 |
18 | var node: TreeNode? = root
19 | var pre: TreeNode? = null
20 |
21 | while (node != null) {
22 | pre = node
23 | if (node.value > target) {
24 | node = node.left
25 | } else if (node.value < target) {
26 | node = node.right
27 | } else {
28 | }
29 | }
30 |
31 | if (node == null && pre != null) {
32 | node = TreeNode(target)
33 | if (node!!.value > pre.value) {
34 | pre.right = node
35 | } else {
36 | pre.left = node
37 | }
38 | }
39 |
40 | return root
41 | }
42 |
43 |
44 | // recursion
45 | private fun insert1(root: TreeNode?, target: Int): TreeNode? {
46 | if (root == null) {
47 | val node = TreeNode(target)
48 | return node
49 | }
50 |
51 | if (root.value > target) {
52 | root.left = insert(root.left, target)
53 | }
54 |
55 | if (root.value < target) {
56 | root.right = insert(root.right, target)
57 | }
58 |
59 | return root
60 | }
61 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/bst/Med_98_ValidateBST.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.bst
2 |
3 | import com.boycoder.basis.datastructure.TreeNode
4 | import java.util.*
5 |
6 | /**
7 | * @Author: zhutao
8 | * @datetime: 2021/6/4
9 | * @desc:
10 | */
11 | object Med_98_ValidateBST {
12 | fun isValidBST(root: TreeNode?): Boolean {
13 | return isValid(root)
14 | }
15 |
16 | // in order traversal and check if is sorted
17 | private fun isValid(root: TreeNode?): Boolean {
18 | if (root == null) return true
19 |
20 | val stk = LinkedList()
21 | stk.addLast(root)
22 | var node: TreeNode? = null
23 | val list = mutableListOf()
24 | var pre: TreeNode? = null
25 |
26 | while (!stk.isEmpty()) {
27 | node = stk.getLast() // peek
28 |
29 | if (node != null) {
30 | node = stk.removeLast()
31 | // in order
32 |
33 | node?.right?.let {
34 | stk.addLast(it)
35 | }
36 |
37 |
38 | stk.addLast(node)
39 | stk.addLast(null)
40 |
41 | node?.left?.let {
42 | stk.addLast(it)
43 | }
44 | } else {
45 | stk.removeLast()
46 | node = stk.removeLast()?:continue
47 |
48 | if (pre != null && pre.value >= node.value) {
49 | return false
50 | }
51 | pre = node
52 | }
53 | }
54 |
55 | return true
56 | }
57 |
58 | // in order traversal and check if is sorted
59 | private fun isValid1(root: TreeNode?): Boolean {
60 | if (root == null) return true
61 |
62 | val stk = LinkedList()
63 | stk.addLast(root)
64 | var node: TreeNode? = null
65 | val list = mutableListOf()
66 |
67 | while (!stk.isEmpty()) {
68 | node = stk.getLast() // peek
69 |
70 | if (node != null) {
71 | node = stk.removeLast()
72 | // in order
73 |
74 | node?.right?.let {
75 | stk.addLast(it)
76 | }
77 |
78 |
79 | stk.addLast(node)
80 | stk.addLast(null)
81 |
82 | node?.left?.let {
83 | stk.addLast(it)
84 | }
85 | } else {
86 | stk.removeLast()
87 | node = stk.removeLast()
88 |
89 | node?.let {
90 | list.add(it.value)
91 | }
92 | }
93 | }
94 |
95 | // traversal and check
96 | var pre = list[0]
97 | for (i in 1..(list.size - 1)) {
98 | if (pre >= list[i]) {
99 | return false
100 | }
101 | pre = list[i]
102 | }
103 |
104 | return true
105 | }
106 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/dp/Easy_062_UniquePath.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.dp
2 |
3 | import com.boycoder.utils.WrongResultException
4 | import com.boycoder.utils.asserts
5 |
6 | /**
7 | For the path(m, n), it comes from path(m - 1, n) and path(m, n - 1)
8 | 1. recursion
9 | 2. recursion + cache + state compress
10 | 3. dp
11 | */
12 | object Easy_062_UniquePath {
13 | var cache: IntArray = intArrayOf()
14 | val BASE = 101
15 |
16 | fun uniquePaths(m: Int, n: Int): Int {
17 | return path3(m, n)
18 | }
19 |
20 | // dp
21 | private fun path3(m: Int, n: Int): Int {
22 | // dp with init
23 | val dp: Array = Array(m + 1){ IntArray(n + 1){1} }
24 |
25 | for (i in 2..m) {
26 | for (j in 2..n) {
27 | dp[i][j] = dp[i][j - 1] + dp[i - 1][j]
28 | }
29 | }
30 |
31 | return dp[m][n]
32 | }
33 |
34 | // out of time
35 | private fun path1(m: Int, n: Int): Int {
36 | if (m == 1 || n == 1) return 1
37 |
38 | return path1(m, n - 1) + path1(m - 1, n)
39 | }
40 |
41 | // recursion + cache + state compress
42 | private fun path2(state: Int): Int {
43 | val m = state / BASE
44 | val n = state % BASE
45 |
46 | if (m == 1 || n == 1) return 1
47 |
48 | if (cache[state] != 0) {
49 | return cache[state]
50 | }
51 |
52 | val res = path2(m * BASE + n - 1) + path2((m - 1) * BASE + n)
53 | cache[state] = res
54 |
55 | return res
56 | }
57 | }
58 | fun main() {
59 | val res = Easy_062_UniquePath.uniquePaths(3, 7)
60 | asserts(res, 28)
61 | println(res)
62 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/dp/Easy_070_ClimbStairs.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.dp
2 |
3 | import com.boycoder.utils.asserts
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/3
8 | * @desc:
9 | */
10 | object Easy_070_ClimbStairs {
11 | private val cache = hashMapOf()
12 | fun climbStairs(n: Int): Int {
13 | return climb2(n)
14 | }
15 |
16 | // dp
17 | private fun climb(n: Int): Int {
18 | if (n == 1) return 1
19 | if (n == 2) return 2
20 |
21 | val dp = IntArray(n + 1)
22 |
23 | dp[1] = 1
24 | dp[2] = 2
25 |
26 | for (i in 3..n) {
27 | dp[i] = dp[i - 1] + dp[i - 2]
28 | }
29 |
30 | return dp[n]
31 | }
32 |
33 | /**
34 | * This problems is similar to [com.boycoder.problems.dp.knapsack.Med_377_CombinationSumIV.count3]
35 | * We got array:[1,2], and target n
36 | * Get all the permutations count.
37 | * So it become a knapsack problem.
38 | */
39 | private fun climb2(n: Int): Int {
40 | val dp = IntArray(n + 1)
41 |
42 | dp[0] = 1
43 |
44 | for (i in 1..n) {
45 | for (j in 1..2)
46 | if (i >= j) {
47 | dp[i] = dp[i] + dp[i - j]
48 | }
49 | }
50 |
51 | return dp[n]
52 | }
53 |
54 | // recursion + cache
55 | private fun climb1(n: Int): Int {
56 | if (n == 1) return 1
57 | if (n == 2) return 2
58 |
59 | if (cache.getOrDefault(n, 0) != 0) {
60 | return cache.getOrDefault(n, 0)
61 | }
62 |
63 | val v = climb(n - 1) + climb(n - 2)
64 | cache.put(n, v)
65 |
66 | return v
67 | }
68 | }
69 |
70 | fun main() {
71 | val res = Easy_070_ClimbStairs.climbStairs(3)
72 | asserts(res, 3)
73 | println(res)
74 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/dp/Easy_509_Fibonacci.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.dp
2 |
3 | import com.boycoder.utils.asserts
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/3
8 | * @desc:
9 | */
10 | object Easy_509_Fibonacci {
11 | private val cache = IntArray(31)
12 |
13 | fun fib(n: Int): Int {
14 | return count(n)
15 | }
16 |
17 | // dp + space optimize
18 | // a little bit like slide window
19 | private fun count(n: Int): Int {
20 | if (n == 0) return 0
21 | if (n == 1 || n == 2) return 1
22 |
23 | var dp1 = 1
24 | var dp2 = 1
25 |
26 | for (i in 3..n) {
27 | val temp = dp1 + dp2
28 | dp1 = dp2
29 | dp2 = temp
30 | }
31 |
32 | return dp2
33 | }
34 |
35 | // dp
36 | private fun count3(n: Int): Int {
37 | if (n == 0) return 0
38 | if (n == 1 || n == 2) return 1
39 |
40 | val dp = IntArray(31)
41 | dp[1] = 1
42 | dp[2] = 1
43 |
44 | for (i in 3..n) {
45 | dp[i] = dp[i - 1] + dp[i - 2]
46 | }
47 |
48 | return dp[n]
49 | }
50 |
51 | // recursion + cache
52 | private fun count2(n: Int): Int {
53 | if (n == 0) return 0
54 | if (n == 1 || n == 2) return 1
55 |
56 | if (cache[n] != 0) {
57 | return cache[n]
58 | }
59 | val v = count(n - 1) + count(n - 2)
60 | cache[n] = v
61 | return v
62 | }
63 |
64 | // recursion
65 | private fun count1(n: Int): Int {
66 | if (n == 0) return 0
67 | if (n == 1 || n == 2) return 1
68 | return count(n - 1) + count(n - 2)
69 | }
70 | }
71 |
72 | fun main() {
73 | val res = Easy_509_Fibonacci.fib(4)
74 | asserts(res, 4)
75 | println(res)
76 |
77 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/dp/Easy_746_ClimbStairsCost.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.dp
2 |
3 | import com.boycoder.utils.asserts
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/3
8 | * @desc:
9 | */
10 | object Easy_746_ClimbStairsCost {
11 | private var cost: IntArray = intArrayOf()
12 | private var cache = intArrayOf()
13 |
14 | fun minCostClimbingStairs(cost: IntArray): Int {
15 | this.cost = cost
16 | cache = IntArray(cost.size + 1)
17 | return min(cost.size)
18 | }
19 |
20 | // dp
21 | private fun min(n: Int): Int {
22 | val dp = IntArray(n + 1)
23 | dp[0] = cost[0]
24 | dp[1] = cost[1]
25 |
26 | for (i in 2..n) {
27 | val cost = cost.getOrNull(i)?:0
28 | dp[i] = Math.min(dp[i - 1], dp[i - 2]) + cost
29 | }
30 |
31 | return dp[n]
32 | }
33 |
34 | /**
35 | * To get to n, we need to pay: Math.min(dfs(n - 1) + cost[n], dfs(n - 2) + cost[n])
36 | */
37 | private fun min1(n: Int): Int {
38 | if (n == 0) return cost[0]
39 | if (n == 1) return cost[1]
40 |
41 | if (cache[n] != 0) {
42 | return cache[n]
43 | }
44 |
45 | val v = cost.getOrNull(n)?:0
46 | val res = Math.min(min1(n - 1) + v, min1(n - 2) + v)
47 | cache[n] = res
48 | return res
49 | }
50 | }
51 |
52 | fun main() {
53 | val res = Easy_746_ClimbStairsCost.minCostClimbingStairs(intArrayOf(1, 100, 1, 1, 1, 100, 1, 1, 100, 1))
54 | asserts(res, 6)
55 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/dp/Med_096_UniqueBST.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.dp
2 |
3 | import com.boycoder.utils.asserts
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/3
8 | * @desc:
9 | */
10 | /**
11 | Ideal
12 | For an array, we pick a position to generate the BST,
13 | the left side become left child, right side become right child.
14 | For the child, it can split until it become 1
15 | */
16 | object Med_096_UniqueBST {
17 | private var cache = intArrayOf()
18 | fun numTrees(n: Int): Int {
19 | // cache = IntArray(n + 1)
20 | return num(n)
21 | }
22 |
23 | // dp
24 | private fun num(n: Int): Int {
25 | val dp = IntArray(n + 1)
26 |
27 | dp[0] = 1
28 | dp[1] = 1
29 |
30 | for (i in 2..n) {
31 | for (j in 0 until i) {
32 | dp[i] = dp[i] + dp[j] * dp[i - j - 1]
33 | }
34 | }
35 |
36 | return dp[n]
37 | }
38 |
39 | // recursion + cache
40 | private fun num2(n: Int): Int {
41 | if (n == 0) return 1
42 | if (n == 1) return 1
43 | if (n == 2) return 2
44 |
45 | if (cache[n] != 0) {
46 | return cache[n]
47 | }
48 |
49 | var count = 0
50 | for (i in 0 until n) {
51 | count = count + num2(i) * num2(n - i - 1)
52 | }
53 |
54 | cache[n] = count
55 |
56 | return count
57 | }
58 |
59 | // recursion
60 | private fun num1(n: Int): Int {
61 | if (n == 0) return 1
62 | if (n == 1) return 1
63 | if (n == 2) return 2
64 |
65 | var count = 0
66 | for (i in 0 until n) {
67 | count = count + num1(i) * num1(n - i - 1)
68 | }
69 |
70 | return count
71 | }
72 | }
73 |
74 | fun main() {
75 | val res = Med_096_UniqueBST.numTrees(3)
76 | asserts(res, 5)
77 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/dp/Med_343_IntegerBreak.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.dp
2 |
3 | import com.boycoder.utils.asserts
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/3
8 | * @desc:
9 | */
10 | /**
11 | 6 7 8 9
12 | 1, 5 1,6 1,7 1,8
13 | 3, 3 2,5 2,6 2,7
14 | 3,4 3,5 3,6
15 | 4,5
16 |
17 | break(i) = (2 * max(break(i - 2), i - 2), 3 * max(break(i - 3), i - 3)
18 | */
19 | object Med_343_IntegerBreak {
20 | private var cache = intArrayOf()
21 |
22 | fun integerBreak(n: Int): Int {
23 | cache = IntArray(n + 1)
24 |
25 | return maxInt(n)
26 | }
27 |
28 | /**
29 | dp
30 | */
31 | private fun maxInt(n: Int): Int {
32 | // space can be optimize
33 | val dp = IntArray(n + 1)
34 | dp[2] = 1
35 |
36 |
37 | for (i in 3..n) {
38 | val index = (i + 1) / 2
39 | for (j in 2..index) {
40 | dp[i] = Math.max(dp[i], Math.max(dp[i - j], i - j) * Math.max(dp[j], j))
41 | }
42 | }
43 |
44 | return dp[n]
45 | }
46 |
47 | // recursion + cache
48 | private fun maxInt1(n: Int): Int {
49 | if (n == 2) return 1
50 | if (n == 3) return 2
51 | if (n == 4) return 4
52 |
53 | if (cache[n] != 0) {
54 | return cache[n]
55 | }
56 |
57 | var res = 0
58 | val index = (n + 1) / 2
59 |
60 | for (i in 2..index) {
61 | res = Math.max(res, Math.max(maxInt1(n - i), n - i) * Math.max(maxInt1(i), i))
62 | }
63 |
64 | cache[n] = res
65 |
66 | return res
67 | }
68 | }
69 |
70 | fun main() {
71 | val res = Med_343_IntegerBreak.integerBreak(8)
72 | asserts(res, 18)
73 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/dp/editdistance/Easy_392_IsSubSequence.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.dp.editdistance
2 |
3 | import com.boycoder.utils.asserts
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/17
8 | * @desc: https://leetcode-cn.com/problems/is-subsequence/
9 | * 1. two pointer
10 | * 2. dfs
11 | * 3. dp
12 | */
13 | object Easy_392_IsSubSequence {
14 | var array1 = charArrayOf()
15 | var array2 = charArrayOf()
16 |
17 | fun isSubsequence(s: String, t: String): Boolean {
18 | array1 = s.toCharArray()
19 | array2 = t.toCharArray()
20 | return dp()
21 | }
22 |
23 | /**
24 | * The basic case of Edit Distance
25 | *
26 | * dp[i][j] means the LCS length
27 | * Check dp[array1.size][array2.size] == array1.size
28 | */
29 | private fun dp(): Boolean {
30 | val dp = Array(array1.size + 1) { IntArray(array2.size + 1)}
31 |
32 | for (i in 1..array1.size) {
33 | for (j in 1..array2.size) {
34 | if (array1[i - 1] == array2[j - 1]) {
35 | dp[i][j] = dp[i - 1][j - 1] + 1
36 | } else {
37 | /**
38 | * Here is little bit tricky
39 | * |
40 | * abc
41 | * ahbgdc
42 | * |
43 | * Because array1[2] != array2[3]
44 | * So dp[2][3] = dp[2][2]
45 | */
46 | dp[i][j] = dp[i][j - 1]
47 | }
48 | }
49 | }
50 |
51 | return dp[array1.size][array2.size] == array1.size
52 | }
53 |
54 | /**
55 | * dp
56 | *
57 | * Bottom to top
58 | *
59 | * dp[i][j] means the result of array1[0, i-1] array2[0, j-1]
60 | */
61 | private fun dp1(): Boolean {
62 | val dp = Array(array1.size) { BooleanArray(array2.size) }
63 |
64 | // init when i = 0
65 | for (j in 0 until array2.size) {
66 | if (array2[j] == array1[0]) {
67 | for (k in j until array2.size) {
68 | dp[0][k] = true
69 | }
70 | break
71 | }
72 | }
73 |
74 | // init when j = 0, by default is false
75 |
76 | for (i in 1 until array1.size) {
77 | for (j in 1 until array2.size) {
78 | if (dp[i][j - 1]) {
79 | dp[i][j] = true
80 | } else {
81 | if (array1[i] == array2[j]) {
82 | dp[i][j] = dp[i - 1][j - 1]
83 | }
84 | }
85 | }
86 | }
87 |
88 | return dp[array1.size - 1][array2.size - 1]
89 | }
90 |
91 | /**
92 | * dfs
93 | *
94 | * Try to break it down into smaller problems
95 | */
96 | private fun isValid1(end1: Int, end2: Int): Boolean {
97 | if (end1 < 0) {
98 | return true
99 | } else if (end2 < 0) {
100 | return false
101 | }
102 |
103 | return if (array1[end1] == array2[end2]) {
104 | isValid1(end1 - 1, end2 - 1)
105 | } else {
106 | isValid1(end1, end2 - 1)
107 | }
108 | }
109 |
110 | /**
111 | * check s is subsequence of t.
112 | */
113 | private fun isValid(s: String, t: String): Boolean {
114 | // two pointer go through two string.
115 | var start1 = 0
116 | var start2 = 0
117 |
118 | val array1 = s.toCharArray()
119 | val array2 = t.toCharArray()
120 |
121 | while (start1 < s.length && start2 < t.length) {
122 | if (array1[start1] == array2[start2]) {
123 | start1++
124 | start2++
125 | } else {
126 | start2++
127 | }
128 | }
129 |
130 | return start1 == s.length
131 | }
132 | }
133 |
134 | fun main() {
135 | val res = Easy_392_IsSubSequence.isSubsequence("abc", "ahbgdc")
136 | asserts(res, true)
137 | val res1 = Easy_392_IsSubSequence.isSubsequence("axc", "ahbgdc")
138 | asserts(res1, false)
139 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/dp/editdistance/Hard_115_DistinctSubSequence.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.dp.editdistance
2 |
3 | import com.boycoder.utils.asserts
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/19
8 | * @desc: https://leetcode-cn.com/problems/distinct-subsequences/
9 | *
10 | * dfs
11 | * dp
12 | */
13 | object Hard_115_DistinctSubSequence {
14 | private var array1 = charArrayOf()
15 | private var array2 = charArrayOf()
16 |
17 | private val memo = hashMapOf()
18 | fun numDistinct(s: String, t: String): Int {
19 | array1 = s.toCharArray()
20 | array2 = t.toCharArray()
21 | memo.clear()
22 | return count2()
23 | }
24 |
25 | /**
26 | * dp[i][j] means array1[0, i -1] and array2[0, j - 1] count
27 | */
28 | private fun count2(): Int {
29 | val dp = Array(array1.size + 1) { IntArray(array2.size + 1)}
30 |
31 | // init when t is empty string
32 | for (i in 0..array1.size) {
33 | dp[i][0] = 1
34 | }
35 |
36 | // init when s is empty string
37 | for (j in 1..array2.size) {
38 | dp[0][j] = 0
39 | }
40 |
41 | for (i in 1..array1.size) {
42 | for (j in 1..array2.size) {
43 | if (array1[i - 1] == array2[j - 1]) {
44 | // use (i - 1) or not
45 | dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j]
46 | } else {
47 | dp[i][j] = dp[i - 1][j]
48 | }
49 | }
50 | }
51 |
52 | return dp[array1.size][array2.size]
53 | }
54 |
55 | /**
56 | * dfs + cache
57 | */
58 | private fun count1(end1: Int, end2: Int): Int {
59 | // base case
60 | if (end2 < 0) {
61 | return 1
62 | }
63 |
64 | if (end1 < 0) {
65 | return 0
66 | }
67 |
68 | val key = "${end1}.${end2}"
69 | if (memo.containsKey(key)) {
70 | return memo.getOrDefault(key, 0)
71 | }
72 |
73 | var res = 0
74 | if (array1[end1] == array2[end2]) {
75 | res = count1(end1 - 1, end2 - 1) + count1(end1 - 1, end2)
76 | } else {
77 | res = count1(end1 - 1, end2)
78 | }
79 |
80 | memo[key] = res
81 | return res
82 | }
83 |
84 | /**
85 | * dfs
86 | */
87 | private fun count(end1: Int, end2: Int): Int {
88 | // base case
89 | if (end2 < 0) {
90 | return 1
91 | }
92 |
93 | if (end1 < 0) {
94 | return 0
95 | }
96 |
97 | if (array1[end1] == array2[end2]) {
98 | return count(end1 - 1, end2 - 1) + count(end1 - 1, end2)
99 | } else {
100 | return count(end1 - 1, end2)
101 | }
102 | }
103 | }
104 |
105 | fun main() {
106 | val res = Hard_115_DistinctSubSequence.numDistinct("rabbbit", "rabbit")
107 | asserts(res, 3)
108 | val res1 = Hard_115_DistinctSubSequence.numDistinct("babgbag", "bag")
109 | asserts(res1, 5)
110 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/dp/editdistance/Hard_72_EditDistance.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.dp.editdistance
2 |
3 | import com.boycoder.utils.asserts
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/20
8 | * @desc: https://leetcode-cn.com/problems/edit-distance/
9 | */
10 | object Hard_72_EditDistance {
11 | var array1 = charArrayOf()
12 | var array2 = charArrayOf()
13 |
14 | val memo = hashMapOf()
15 |
16 | fun minDistance(word1: String, word2: String): Int {
17 | array1 = word1.toCharArray()
18 | array2 = word2.toCharArray()
19 | return distance2()
20 | }
21 |
22 | /**
23 | * dp
24 | *
25 | * dp[i][j] means array1[0, i - 1] array2[0, j - 1] edit distance
26 | */
27 | private fun distance2(): Int {
28 | val dp = Array(array1.size + 1) { IntArray(array2.size + 1) }
29 |
30 | // init when word2 is empty string
31 | for (i in 0..array1.size) {
32 | dp[i][0] = i
33 | }
34 |
35 | // init when word1 is empty string
36 | for (j in 0..array2.size) {
37 | dp[0][j] = j
38 | }
39 |
40 | // calculation
41 | for (i in 1..array1.size) {
42 | for (j in 1..array2.size) {
43 | if (array1[i - 1] == array2[j - 1]) {
44 | dp[i][j] = dp[i - 1][j - 1]
45 | } else {
46 | // delete word1
47 | val res1 = dp[i - 1][j] + 1
48 | // delete word2
49 | val res2 = dp[i][j - 1] + 1
50 | // replace
51 | val res3 = dp[i - 1][j - 1] + 1
52 | dp[i][j] = Math.min(res1, Math.min(res2, res3))
53 | }
54 | }
55 | }
56 |
57 | return dp[array1.size][array2.size]
58 | }
59 |
60 | /**
61 | * dfs + cache
62 | */
63 | private fun distance1(end1: Int, end2: Int): Int {
64 | if (end1 < 0) {
65 | return end2 + 1
66 | }
67 |
68 | if (end2 < 0) {
69 | return end1 + 1
70 | }
71 |
72 | var result = 0
73 | val key = "${end1}.${end2}"
74 | if (memo.containsKey(key)) {
75 | return memo.getOrDefault(key, 0)
76 | }
77 |
78 | if (array1[end1] == array2[end2]) {
79 | result = distance(end1 - 1, end2 - 1)
80 | } else {
81 | // replace
82 | val res1 = distance(end1 - 1, end2 -1) + 1
83 | // delete word1
84 | val res2 = distance(end1 - 1, end2) + 1
85 | // delete word2
86 | val res3 = distance(end1, end2 - 1) + 1
87 |
88 | result = Math.min(res1, Math.min(res2, res3))
89 | }
90 |
91 | memo[key] = result
92 | return result
93 | }
94 |
95 |
96 | /**
97 | * dfs
98 | *
99 | * Try to break it into smaller problems
100 | */
101 | private fun distance(end1: Int, end2: Int): Int {
102 | if (end1 < 0) {
103 | return end2 + 1
104 | }
105 |
106 | if (end2 < 0) {
107 | return end1 + 1
108 | }
109 |
110 | if (array1[end1] == array2[end2]) {
111 | return distance(end1 - 1, end2 - 1)
112 | } else {
113 | // replace
114 | val res1 = distance(end1 - 1, end2 -1) + 1
115 | // delete word1
116 | val res2 = distance(end1 - 1, end2) + 1
117 | // delete word2
118 | val res3 = distance(end1, end2 - 1) + 1
119 |
120 | return Math.min(res1, Math.min(res2, res3))
121 | }
122 | }
123 | }
124 |
125 | fun main() {
126 | val res = Hard_72_EditDistance.minDistance("horse", "ros")
127 | asserts(res, 3)
128 | val res1 = Hard_72_EditDistance.minDistance("intention", "execution")
129 | asserts(res1, 5)
130 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/dp/editdistance/Med_583_DeleteForTwoString.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.dp.editdistance
2 |
3 | import com.boycoder.problems.dp.subsequence.Med_1143_LongestCommonSubsequence
4 | import com.boycoder.utils.asserts
5 |
6 | /**
7 | * @Author: zhutao
8 | * @datetime: 2021/6/19
9 | * @desc:
10 | */
11 | object Med_583_DeleteForTwoString {
12 | var array1 = charArrayOf()
13 | var array2 = charArrayOf()
14 |
15 | val memo = hashMapOf()
16 | fun minDistance(word1: String, word2: String): Int {
17 | array1 = word1.toCharArray()
18 | array2 = word2.toCharArray()
19 |
20 | return distance3()
21 | }
22 |
23 | /**
24 | * dp[i][j] means array1[0, i - 1] array2[0, j - 1] distance
25 | */
26 | private fun distance3(): Int {
27 | val dp = Array(array1.size + 1) {IntArray(array2.size + 1)}
28 |
29 | // init when word2 is empty string
30 | for (i in 0..array1.size) {
31 | dp[i][0] = i
32 | }
33 |
34 | // init when word1 is empty string
35 | for (j in 0..array2.size) {
36 | dp[0][j] = j
37 | }
38 |
39 | for (i in 1..array1.size) {
40 | for (j in 1..array2.size) {
41 | if (array1[i - 1] == array2[j - 1]) {
42 | dp[i][j] = dp[i - 1][j - 1]
43 | } else {
44 | val res1 = dp[i - 1][j] + 1
45 | val res2 = dp[i][j - 1] + 1
46 | val res3 = dp[i - 1][j - 1] + 2
47 | dp[i][j] = Math.min(res1, Math.min(res2, res3))
48 | }
49 | }
50 | }
51 |
52 | return dp[array1.size][array2.size]
53 | }
54 |
55 | /**
56 | * dfs + cache
57 | */
58 | private fun distance2(end1: Int, end2: Int): Int {
59 | if (end1 < 0) {
60 | return end2 + 1
61 | }
62 |
63 | if (end2 < 0) {
64 | return end1 + 1
65 | }
66 |
67 | val key = "${end1}.${end2}"
68 | if (memo.containsKey(key)) {
69 | return memo.getOrDefault(key, 0)
70 | }
71 |
72 | var result = 0
73 |
74 | if (array1[end1] == array2[end2]) {
75 | result = distance1(end1 - 1, end2 - 1)
76 | } else {
77 | val res1 = distance1(end1 - 1, end2) + 1
78 | val res2 = distance1(end1, end2 - 1) + 1
79 | val res3 = distance1(end1 - 1, end2 - 1) + 2
80 | result = Math.min(res1, Math.min(res2, res3))
81 | }
82 |
83 | memo[key] = result
84 | return result
85 | }
86 |
87 | /**
88 | * dfs
89 | */
90 | private fun distance1(end1: Int, end2: Int): Int {
91 | if (end1 < 0) {
92 | return end2 + 1
93 | }
94 |
95 | if (end2 < 0) {
96 | return end1 + 1
97 | }
98 |
99 | if (array1[end1] == array2[end2]) {
100 | return distance1(end1 - 1, end2 - 1)
101 | } else {
102 | val res1 = distance1(end1 - 1, end2) + 1
103 | val res2 = distance1(end1, end2 - 1) + 1
104 | val res3 = distance1(end1 - 1, end2 - 1) + 2
105 | return Math.min(res1, Math.min(res2, res3))
106 | }
107 | }
108 |
109 | /**
110 | * Calculate the size of LCS and return m + n - 2 * LCS
111 | */
112 | private fun distance(word1: String, word2: String): Int {
113 | val lcs = Med_1143_LongestCommonSubsequence.longestCommonSubsequence(word1, word2)
114 | return word1.length + word2.length - 2 * lcs
115 | }
116 | }
117 |
118 | fun main() {
119 | val res = Med_583_DeleteForTwoString.minDistance("sea", "eat")
120 | asserts(res, 2)
121 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/dp/editdistance/Med_647_PalindromicSubString.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.dp.editdistance
2 |
3 | import com.boycoder.utils.asserts
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/20
8 | * @desc: https://leetcode-cn.com/problems/palindromic-substrings/
9 | */
10 | object Med_647_PalindromicSubString {
11 | var array = charArrayOf()
12 | fun countSubstrings(s: String): Int {
13 | array = s.toCharArray()
14 | return count()
15 | }
16 |
17 | private fun count(): Int {
18 | val memo = Array(array.size){ IntArray(array.size){ -1 } }
19 | var res = 0
20 | // split every sub string and check it by using dfs
21 | for (start in 0 until array.size) {
22 | for (end in start until array.size) {
23 | res = res + (if (dfs1(memo, start, end)) 1 else 0)
24 | }
25 | }
26 |
27 | return res
28 | }
29 |
30 | private fun dfs1(memo: Array, start: Int, end: Int): Boolean {
31 | if (start == end) return true
32 | if (start + 1 == end) return array[start] == array[end]
33 |
34 | if (memo[start][end] != -1) {
35 | return memo[start][end] == 1
36 | }
37 |
38 | val res = if (array[start] == array[end]) dfs(start + 1, end - 1) else false
39 | memo[start][end] = if (res) 1 else 0
40 |
41 | return res
42 | }
43 |
44 | private fun dfs(start: Int, end: Int): Boolean {
45 | if (start == end) return true
46 | if (start + 1 == end) return array[start] == array[end]
47 |
48 | return if (array[start] == array[end]) dfs(start + 1, end - 1) else false
49 | }
50 | }
51 |
52 | fun main() {
53 | val res = Med_647_PalindromicSubString.countSubstrings("abc")
54 | asserts(res, 3)
55 | val res1 = Med_647_PalindromicSubString.countSubstrings("aaa")
56 | asserts(res1, 6)
57 | }
58 |
--------------------------------------------------------------------------------
/src/com/boycoder/problems/dp/knapsack/Med_322_CoinChange.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.dp.knapsack
2 |
3 | import com.boycoder.utils.asserts
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/15
8 | * @desc: https://leetcode-cn.com/problems/coin-change/
9 | * Similar to the [Med_279_PerfectSquares.find4]
10 | * This problem can use bfs too.
11 | */
12 | object Med_322_CoinChange {
13 | private var min = Int.MAX_VALUE
14 | private var coins = intArrayOf()
15 |
16 | private var memo = hashMapOf()
17 |
18 | fun coinChange(coins: IntArray, amount: Int): Int {
19 | this.coins = coins
20 | val res = change3(amount)
21 | return if (res == Int.MAX_VALUE) -1 else res
22 | }
23 |
24 | /**
25 | * coins[] is value[] and weight[], and amount is capacity.
26 | * We need to know the min amount that fit the knapsack.
27 | * dp[j] means: to fill the j capacity knapsack, min amount is dp[j]
28 | * This is similar to [Med_377_CombinationSumIV.count3]
29 | */
30 | private fun change3(amount: Int): Int {
31 | val dp = IntArray(amount + 1) { Int.MAX_VALUE }
32 | dp[0] = 0
33 |
34 | // loop coins
35 | for (i in 0 until coins.size) {
36 | // loop capacity
37 | for (j in coins[i]..amount) {
38 | if (dp[j - coins[i]] != Int.MAX_VALUE) {
39 | // if it's initialized
40 | dp[j] = Math.min(dp[j], dp[j - coins[i]] + 1)
41 | }
42 | }
43 | }
44 |
45 | return dp[amount]
46 | }
47 |
48 | /**
49 | * dp
50 | * bottom to top
51 | */
52 | private fun change2(amount: Int): Int {
53 | val dp = IntArray(amount + 1)
54 | dp[0] = 0
55 |
56 | /**
57 | * this loop is equal to the recursion [change1]
58 | */
59 | for (i in 1..amount) {
60 | // This loop will count dp[1]/dp[2]/dp[3]...dp[amount]
61 | var min = Int.MAX_VALUE
62 | for (j in 0 until coins.size) {
63 | if (i >= coins[j] && dp[i - coins[j]] < min) {
64 | min = dp[i - coins[j]] + 1
65 | }
66 | }
67 | dp[i] = min
68 | }
69 |
70 | return dp[amount]
71 | }
72 |
73 | /**
74 | * dfs + cache
75 | * For every coin, we can choose more than one time.
76 | */
77 | private fun change1(amount: Int): Int {
78 | if (amount < 0) {
79 | return Int.MAX_VALUE
80 | }
81 |
82 | if (amount == 0) {
83 | return 0
84 | }
85 |
86 | val key = "${amount}"
87 | if (memo.containsKey(key)) {
88 | return memo.getOrDefault(key, Int.MAX_VALUE)
89 | }
90 |
91 | var min = Int.MAX_VALUE
92 | for (i in 0 until coins.size) {
93 | var res = change1(amount - coins[i])
94 | if (res != Int.MAX_VALUE) {
95 | res++
96 | }
97 | min = Math.min(min, res)
98 | }
99 |
100 | memo[key] = min
101 | return min
102 | }
103 |
104 | /**
105 | * For every coin, we can choose more than one time.
106 | */
107 | private fun change(size: Int, amount: Int) {
108 | if (amount == 0) {
109 | if (size < min) {
110 | min = size
111 | }
112 | return
113 | }
114 |
115 | if (amount < 0) {
116 | return
117 | }
118 |
119 | for (i in 0 until coins.size) {
120 | change(size + 1, amount - coins[i])
121 | }
122 | }
123 | }
124 |
125 | fun main() {
126 | val res = Med_322_CoinChange.coinChange(intArrayOf(1, 2, 5), 11)
127 | asserts(res, 3)
128 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/dp/knapsack/Med_377_CombinationSumIV.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.dp.knapsack
2 |
3 | import com.boycoder.utils.asserts
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/15
8 | * @desc: https://leetcode-cn.com/problems/combination-sum-iv/
9 | */
10 | object Med_377_CombinationSumIV {
11 | var array = intArrayOf()
12 | var target = 0
13 |
14 | var count = 0
15 | var memo = hashMapOf()
16 |
17 | fun combinationSum4(nums: IntArray, target: Int): Int {
18 | this.array = nums
19 | this.target = target
20 | this.count = 0
21 | return count3()
22 | }
23 |
24 | /**
25 | * dp[i] means, to get target i, we can get dp[i] permutations
26 | */
27 | private fun count3(): Int {
28 | val dp = IntArray(target + 1)
29 | dp[0] = 1
30 |
31 | /**
32 | * To get permutations count, we loop capacity then loop value
33 | * This is different from [Med_518_CoinChangeII.find5]
34 | */
35 | for (i in 1..target) {
36 | for (j in 0 until array.size) {
37 | if (i >= array[j])
38 | dp[i] = dp[i] + dp[i - array[j]]
39 | }
40 | }
41 |
42 | return dp[target]
43 | }
44 |
45 | /**
46 | * dfs + cache
47 | */
48 | private fun count2(target: Int): Int {
49 | if (target == 0) return 1
50 |
51 | if (memo.containsKey(target)) {
52 | return memo.getOrDefault(target, 0)
53 | }
54 |
55 | var res = 0
56 |
57 | /**
58 | * To get the permutations count.
59 | * Every time, we loop the whole array.
60 | */
61 | for (num in array) {
62 | if (target >= num) {
63 | res = res + count2(target - num)
64 | }
65 | }
66 | memo[target] = res
67 |
68 | return res
69 | }
70 |
71 | /**
72 | * dfs
73 | */
74 | private fun count1(target: Int): Int {
75 | if (target == 0) return 1
76 | var res = 0
77 |
78 | /**
79 | * To get the permutations count.
80 | * Every time, we loop the whole array.
81 | */
82 | for (num in array) {
83 | if (target >= num) {
84 | res = res + count1(target - num)
85 | }
86 | }
87 | return res
88 | }
89 |
90 | /**
91 | * dfs that can get all the permutations
92 | * If we need the permutations, we can use a path to store.
93 | */
94 | private fun count(target: Int) {
95 | if (target < 0) return
96 | if (target == 0) {
97 | count++
98 | return
99 | }
100 |
101 | for (i in 0 until array.size) {
102 |
103 | count(target - array[i])
104 | }
105 | }
106 | }
107 |
108 | fun main() {
109 | val res = Med_377_CombinationSumIV.combinationSum4(intArrayOf(1, 2, 3), 4)
110 | asserts(res, 7)
111 | val res1 = Med_377_CombinationSumIV.combinationSum4(intArrayOf(9), 3)
112 | asserts(res1, 0)
113 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/dp/robber/Med_198_HouseRobber.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.dp.robber
2 |
3 | import com.boycoder.utils.asserts
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/16
8 | * @desc:
9 | */
10 | object Med_198_HouseRobber {
11 | private var array = intArrayOf()
12 | private var memo = intArrayOf()
13 |
14 | fun rob(nums: IntArray): Int {
15 | array = nums
16 | memo = IntArray(nums.size){ -1 }
17 | return dp()
18 | }
19 |
20 | /**
21 | * dp
22 | *
23 | * bottom to top
24 | *
25 | * dp[i] means, for [0, 1] array, we can the max value
26 | *
27 | * dp[i] = Math.max(dp[i - 2] + array[i], dp[i - 1])
28 | */
29 | private fun dp(): Int {
30 | val size = array.size
31 | // corner case
32 | if (size == 1) return array[0]
33 | if (size == 2) return Math.max(array[1], array[0])
34 |
35 | val dp = IntArray(array.size) { -1 }
36 | dp[0] = array[0]
37 | dp[1] = Math.max(array[1], array[0])
38 |
39 | for (i in 2 until size) {
40 | dp[i] = Math.max(dp[i - 2] + array[i], dp[i - 1])
41 | }
42 |
43 | return dp[size - 1]
44 | }
45 |
46 | /**
47 | * dfs + cache
48 | */
49 | private fun dfs1(end: Int): Int {
50 | if (end == 0) return array[end]
51 | if (end == 1) return Math.max(array[0], array[1])
52 |
53 | if (memo[end] != -1) {
54 | return memo[end]
55 | }
56 |
57 | val res = Math.max(dfs(end - 2) + array[end], dfs(end - 1))
58 |
59 | memo[end] = res
60 | return res
61 | }
62 |
63 | /**
64 | * dfs
65 | *
66 | * Break the array into smaller array
67 | */
68 | private fun dfs(end: Int): Int {
69 | if (end == 0) return array[end]
70 | if (end == 1) return Math.max(array[0], array[1])
71 |
72 | /**
73 | * If we take the end, then we can take (end - 1), we can just take (end - 2)
74 | */
75 | val res = Math.max(dfs(end - 2) + array[end], dfs(end - 1))
76 |
77 | return res
78 | }
79 | }
80 |
81 | fun main() {
82 | val res = Med_198_HouseRobber.rob(intArrayOf(1,2,3,1))
83 | asserts(res, 4)
84 | val res1 = Med_198_HouseRobber.rob(intArrayOf(2,7,9,3,1))
85 | asserts(res1, 12)
86 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/dp/robber/Med_213_HouseRobberII.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.dp.robber
2 |
3 | import com.boycoder.utils.asserts
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/16
8 | * @desc: https://leetcode-cn.com/problems/house-robber-ii/
9 | */
10 | object Med_213_HouseRobberII {
11 |
12 | private var array = intArrayOf()
13 | private var memo = intArrayOf()
14 |
15 | /**
16 | * In this case, because the head and tail of array is connected.
17 | * So, the max value is max(dfs(0, end - 1), dfs(1, end)), and end = size - 1
18 | */
19 | fun rob(nums: IntArray): Int {
20 | // Be careful here, ArrayIndexOutOfBoundsException
21 | if (nums.size == 1) return nums[0]
22 |
23 | this.array = nums
24 | this.memo = IntArray(array.size){ -1 }
25 | val end = nums.size - 1
26 | val memo1 = IntArray(array.size){ -1 }
27 | val memo2 = IntArray(array.size){ -1 }
28 | // return Math.max(dfs1(0, end - 1, memo1), dfs1(1, end, memo2))
29 | return Math.max(dp(0, end - 1), dp(1, end))
30 | }
31 |
32 | private fun dp(start: Int, end: Int): Int {
33 | val dp = IntArray(end + 1) { -1 }
34 |
35 | if (end == start) return array[start]
36 | if (end - start == 1) return Math.max(array[start], array[end])
37 |
38 | dp[start] = array[start]
39 | dp[start + 1] = Math.max(array[start], array[start + 1])
40 |
41 | // calculate dp[start + 1] to dp[end]
42 | for (i in (start + 2)..end) {
43 | dp[i] = Math.max(dp[i - 2] + array[i], dp[i - 1])
44 | }
45 |
46 | return dp[end]
47 | }
48 |
49 | /**
50 | * Because the dfs1 will be called two times from outside.
51 | * So, we can not just use one memo array to cache.
52 | * To solve this problem, we can pass two memo array.
53 | */
54 | private fun dfs1(start: Int, end: Int, memo: IntArray): Int {
55 | if (end == start) return array[end]
56 | if (end == start + 1) return Math.max(array[start], array[start + 1])
57 |
58 | if (memo[end] != -1) {
59 | return memo[end]
60 | }
61 | /**
62 | * If we take the end, then we can take (end - 1), we can just take (end - 2)
63 | */
64 | val res = Math.max(dfs1(start, end - 2, memo) + array[end], dfs1(start, end - 1, memo))
65 |
66 | memo[end] = res
67 | return res
68 | }
69 |
70 | /**
71 | * dfs
72 | *
73 | * Break the array into smaller array
74 | * Time out
75 | */
76 | private fun dfs(start: Int, end: Int): Int {
77 | if (end == start) return array[end]
78 | if (end == start + 1) return Math.max(array[start], array[start + 1])
79 |
80 | /**
81 | * If we take the end, then we can take (end - 1), we can just take (end - 2)
82 | */
83 | val res = Math.max(dfs(start, end - 2) + array[end], dfs(start, end - 1))
84 |
85 | return res
86 | }
87 | }
88 |
89 | fun main() {
90 | val res = Med_213_HouseRobberII.rob(intArrayOf(2,3,2))
91 | asserts(res, 3)
92 | val res1 = Med_213_HouseRobberII.rob(intArrayOf(1,2,3,1))
93 | asserts(res1, 4)
94 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/dp/stock/Med_121_SellStock.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.dp.stock
2 |
3 | import com.boycoder.utils.asserts
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/16
8 | * @desc:
9 | */
10 | object Med_121_SellStock {
11 | fun maxProfit(array: IntArray): Int {
12 | return max3(array)
13 | }
14 |
15 | /**
16 | * dp
17 | *
18 | * dp[i][0] means hold stock the max profit
19 | * dp[i][1] means sell stock the max profit
20 | *
21 | * dp[i][0] = max(dp[i - 1][0], -price[i])
22 | * dp[i][1] = max(dp[1 - 1][1], dp[i - 1][0] + price[i])
23 | */
24 | private fun max3(price: IntArray): Int {
25 | val dp = Array(price.size) { IntArray(2) }
26 |
27 | // first day to hold stock
28 | dp[0][0] = -price[0]
29 |
30 | // first day to not hold stock
31 | dp[0][1] = 0
32 |
33 | for (i in 1 until price.size) {
34 | dp[i][0] = Math.max(dp[i - 1][0], -price[i])
35 | dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] + price[i])
36 | }
37 |
38 | // max profit must sell stock
39 | return dp[price.size - 1][1]
40 | }
41 |
42 | /**
43 | * dfs
44 | * Try to break the array into smaller array.
45 | * When array.size = 1, low = array[0], and profit = 0.
46 | * Use res[0] for lowest price, and res[1] for the max profit
47 | */
48 | private fun max2(array: IntArray, end: Int): IntArray {
49 | if (end == 0) return intArrayOf(array[0], 0)
50 |
51 | val res = max2(array, end - 1)
52 | val max = Math.max(res[1], array[end] - res[0])
53 | val low = Math.min(array[end], res[0])
54 |
55 | return intArrayOf(low, max)
56 | }
57 |
58 | /**
59 | * Greedy
60 | * There is no need to loop the array two times.
61 | */
62 | private fun max1(array: IntArray): Int {
63 | var low = Int.MAX_VALUE
64 | var max = 0
65 |
66 | for (i in array) {
67 | low = Math.min(low, i)
68 | max = Math.max(max, i - low)
69 | }
70 |
71 | return max
72 | }
73 |
74 | /**
75 | * Brute Force
76 | * Two loop, buy loop the [0, size)
77 | * sell loop [i + 1, size)
78 | * Then we find the max profit
79 | */
80 | private fun max(array: IntArray): Int {
81 | var max = 0
82 |
83 | for (buy in 0 until array.size) {
84 | for (sell in buy + 1 until array.size) {
85 | if (array[sell] - array[buy] > max) {
86 | max = array[sell] - array[buy]
87 | }
88 | }
89 | }
90 |
91 | return max
92 | }
93 | }
94 |
95 | fun main() {
96 | val res = Med_121_SellStock.maxProfit(intArrayOf(7, 1, 5, 3, 6, 4))
97 | asserts(res, 5)
98 | val res1 = Med_121_SellStock.maxProfit(intArrayOf(7,6,4,3,1))
99 | asserts(res1, 0)
100 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/dp/stock/Med_122_SellStockII.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.dp.stock
2 |
3 | import com.boycoder.utils.asserts
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/16
8 | * @desc: https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/
9 | */
10 | object Med_122_SellStockII {
11 | fun maxProfit(array: IntArray): Int {
12 | return max1(array)
13 | }
14 |
15 | /**
16 | * dp
17 | *
18 | * dp[i][0] means hold stock, the max profit
19 | * dp[i][1] means not hold stock, the max profit
20 | */
21 | private fun max1(price: IntArray): Int {
22 | val dp = Array(price.size) {IntArray(2)}
23 |
24 | // first day hold stock
25 | dp[0][0] = -price[0]
26 | // first day not hold stock
27 | dp[0][1] = 0
28 |
29 | for (i in 1 until price.size) {
30 | // yesterday already hold or yesterday not hold, but buy today
31 | dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] - price[i])
32 | // yesterday already not hold or yesterday hold, but today sell
33 | dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] + price[i])
34 | }
35 |
36 | return dp[price.size - 1][1]
37 | }
38 |
39 | /**
40 | * Greedy
41 | * Collect all the raising range
42 | */
43 | private fun max(price: IntArray): Int {
44 | var max = 0
45 | for (i in 1 until price.size) {
46 | if (price[i] > price[i - 1]) {
47 | max = max + price[i] - price[i - 1]
48 | }
49 | }
50 |
51 | return max
52 | }
53 | }
54 |
55 | fun main() {
56 | val res = Med_122_SellStockII.maxProfit(intArrayOf(7, 1, 5, 3, 6, 4))
57 | asserts(res, 7)
58 | val res1 = Med_122_SellStockII.maxProfit(intArrayOf(1,2,3,4,5))
59 | asserts(res1, 4)
60 | val res2 = Med_122_SellStockII.maxProfit(intArrayOf(7,6,4,3,1))
61 | asserts(res2, 0)
62 | }
63 |
64 |
--------------------------------------------------------------------------------
/src/com/boycoder/problems/dp/stock/Med_123_SellStockIII.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.dp.stock
2 |
3 | import com.boycoder.utils.asserts
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/16
8 | * @desc: https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iii/
9 | */
10 | object Med_123_SellStockIII {
11 | fun maxProfit(array: IntArray): Int {
12 | return max(array)
13 | }
14 |
15 | /**
16 | * dp
17 | *
18 | * dp[i][0] means no operation
19 | * dp[i][1] means first time buy
20 | * dp[i][2] means first time sell
21 | * dp[i][3] means second time buy
22 | * dp[i][4] means second time sell
23 | *
24 | * dp[i][0] = 0
25 | * dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - price[i])
26 | * dp[i][2] = Math.max(dp[i - 1][2], dp[i - 1][1] + price[i])
27 | * dp[i][3] = Math.max(dp[i - 1][3], dp[i - 1][2] - price[i])
28 | * dp[i][4] = Math.max(dp[i - 1][4], dp[i - 1][3] + price[i])
29 | */
30 | private fun max(price: IntArray): Int {
31 | val dp = Array(price.size) { IntArray(5) }
32 |
33 | // init
34 | dp[0][0] = 0
35 | dp[0][1] = -price[0]
36 | dp[0][2] = 0
37 | dp[0][3] = -price[0]
38 | dp[0][4] = 0
39 |
40 | for (i in 1 until price.size) {
41 | dp[i][0] = 0
42 | dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - price[i])
43 | dp[i][2] = Math.max(dp[i - 1][2], dp[i - 1][1] + price[i])
44 | dp[i][3] = Math.max(dp[i - 1][3], dp[i - 1][2] - price[i])
45 | dp[i][4] = Math.max(dp[i - 1][4], dp[i - 1][3] + price[i])
46 | }
47 |
48 | return dp[price.size - 1][4]
49 | }
50 | }
51 |
52 | fun main() {
53 | val res = Med_123_SellStockIII.maxProfit(intArrayOf(3, 3, 5, 0, 0, 3, 1, 4))
54 | asserts(res, 6)
55 | val res1 = Med_123_SellStockIII.maxProfit(intArrayOf(1, 2, 3, 4, 5))
56 | asserts(res1, 4)
57 | val res2 = Med_123_SellStockIII.maxProfit(intArrayOf(7, 6, 4, 3, 1))
58 | asserts(res2, 0)
59 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/dp/stock/Med_188_SellStockIV.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.dp.stock
2 |
3 | import com.boycoder.utils.asserts
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/16
8 | * @desc: https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iv/
9 | * This problem is based on [Med_123_SellStockIII]
10 | */
11 | object Med_188_SellStockIV {
12 | fun maxProfit(k: Int, array: IntArray): Int {
13 | return max(k, array)
14 | }
15 |
16 | /**
17 | * dp[i][2 * k + 1]
18 | *
19 | * dp[i][0] means no operation
20 | * dp[i][1] means first time buy
21 | * dp[i][2] means first time sell
22 | * dp[i][3] means second time buy
23 | * dp[i][4] means second time sell
24 | *
25 | * dp[i][0] = 0
26 | * dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - price[i])
27 | * dp[i][2] = Math.max(dp[i - 1][2], dp[i - 1][1] + price[i])
28 | * dp[i][3] = Math.max(dp[i - 1][3], dp[i - 1][2] - price[i])
29 | * dp[i][4] = Math.max(dp[i - 1][4], dp[i - 1][3] + price[i])
30 | */
31 | private fun max(k: Int, price: IntArray): Int {
32 | val dp = Array(price.size) { IntArray(2 * k + 1) }
33 |
34 | // init
35 | for (i in 0..2 * k) {
36 | when {
37 | i == 0 -> dp[0][i] = 0
38 | i % 2 == 1 -> dp[0][i] = -price[0]
39 | i % 2 == 0 -> dp[0][i] = 0
40 | }
41 | }
42 |
43 | for (i in 1 until price.size) {
44 | for(j in 0..2 * k) {
45 | when {
46 | j == 0 -> dp[i][j] = 0
47 | j % 2 == 1 -> dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - 1] - price[i])
48 | j % 2 == 0 -> dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - 1] + price[i])
49 | }
50 | }
51 | }
52 |
53 | return dp[price.size - 1][2*k]
54 | }
55 |
56 | }
57 |
58 | fun main() {
59 | val res = Med_188_SellStockIV.maxProfit(2, intArrayOf(2, 4, 1))
60 | asserts(res, 2)
61 | val res1 = Med_188_SellStockIV.maxProfit(2, intArrayOf(3, 2, 6, 5, 0, 3))
62 | asserts(res1, 7)
63 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/dp/stock/Med_309_SellStockCoolDown.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.dp.stock
2 |
3 | import com.boycoder.utils.asserts
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/16
8 | * @desc: https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/
9 | */
10 | object Med_309_SellStockCoolDown {
11 | fun maxProfit(array: IntArray): Int {
12 | return max(array)
13 | }
14 |
15 | /**
16 | * dp[i][j]
17 | *
18 | * dp[i][0] means hold stock
19 | * dp[i][1] means not hold stock, and after cool down
20 | * dp[i][2] means not hold stock, today sell stock
21 | * dp[i][3] means not hold stock, today is cool down day
22 | *
23 | * from state 1 and 3
24 | * dp[i][0] = Math.max(dp[i - 1][0], Math.max(dp[i - 1][1] - price[i], dp[i - 1][3] - price[i]))
25 | * from itself or 3
26 | * dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][3])
27 | * from state 0
28 | * dp[i][2] = dp[i - 1][0] + price[i]
29 | * from state 2
30 | * dp[i][3] = dp[i - 1][2]
31 | */
32 | private fun max(price: IntArray): Int {
33 | val dp = Array(price.size) { IntArray(4) }
34 |
35 | // init
36 | dp[0][0] = -price[0]
37 | dp[0][1] = 0
38 | dp[0][2] = 0
39 | dp[0][3] = 0
40 |
41 | for (i in 1 until price.size) {
42 | dp[i][0] = Math.max(dp[i - 1][0], Math.max(dp[i - 1][1] - price[i], dp[i - 1][3] - price[i]))
43 | dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][3])
44 | dp[i][2] = dp[i - 1][0] + price[i]
45 | dp[i][3] = dp[i - 1][2]
46 | }
47 |
48 | return Math.max(dp[price.size - 1][1], Math.max(dp[price.size - 1][2], dp[price.size - 1][3]))
49 | }
50 |
51 | }
52 |
53 | fun main() {
54 | val res = Med_309_SellStockCoolDown.maxProfit(intArrayOf(1,2,3,0,2))
55 | asserts(res, 3)
56 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/dp/stock/Med_714_SellStockFee.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.dp.stock
2 |
3 | import com.boycoder.utils.asserts
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/16
8 | * @desc:
9 | */
10 | object Med_714_SellStockFee {
11 | /**
12 | * dp[i][j]
13 | *
14 | * dp[i][0] means hold stock
15 | * dp[i][1] means not hold stock
16 | */
17 | fun maxProfit(prices: IntArray, fee: Int): Int {
18 | val dp = Array(prices.size) { IntArray(2) }
19 |
20 | // init
21 | dp[0][0] = -prices[0]
22 | dp[0][1] = 0
23 |
24 | for (i in 1 until prices.size) {
25 | dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] - prices[i])
26 | dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] + prices[i] - fee)
27 | }
28 |
29 | // careful here
30 | return Math.max(dp[prices.size - 1][0], dp[prices.size - 1][1])
31 | }
32 | }
33 |
34 | fun main() {
35 | val res = Med_714_SellStockFee.maxProfit(intArrayOf(1, 3, 2, 8, 4, 9), 2)
36 | asserts(res, 8)
37 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/dp/subsequence/Easy_53_MaxSubArray.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.dp.subsequence
2 |
3 | import com.boycoder.utils.asserts
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/17
8 | * @desc: https://leetcode-cn.com/problems/maximum-subarray/
9 | */
10 | object Easy_53_MaxSubArray {
11 |
12 | private var array = intArrayOf()
13 |
14 | fun maxSubArray(nums: IntArray): Int {
15 | if (nums.size == 0) return 0
16 | this.array = nums
17 | return find1()
18 | }
19 |
20 | /**
21 | * dp
22 | *
23 | * dp[i] means the max sum that end with (i - 1)
24 | * dp[i] = if (dp[i - 1] < 0) array[i] else dp[i - 1] + array[i]
25 | * or
26 | * dp[i] = Math.max(dp[i - 1] + array[i], array[i])
27 | */
28 | private fun find1(): Int {
29 | val dp = IntArray(array.size)
30 | //init
31 | dp[0] = array[0]
32 | var max = dp[0]
33 |
34 | // calculate dp[i] and get max value
35 | for (i in 1 until array.size) {
36 | dp[i] = Math.max(dp[i - 1] + array[i], array[i])
37 | max = Math.max(max, dp[i])
38 | }
39 |
40 | return max
41 | }
42 |
43 | /**
44 | * Greedy + two pointer
45 | * -2,1,-3,4,-1,2,1,-5,4
46 | * |
47 | */
48 | private fun find(): Int{
49 | val size = array.size
50 |
51 | var max = Int.MIN_VALUE
52 | var left = 0
53 | var right = 0
54 |
55 |
56 | while (left < size && right < size) {
57 | var sum = 0
58 | // here can be optimized
59 | for (i in left..right) {
60 | sum = sum + array[i]
61 | }
62 | max = Math.max(max, sum)
63 |
64 | // here control the window slide
65 | if (sum < 0) {
66 | right++
67 | left = right
68 | } else {
69 | right++
70 | }
71 | }
72 |
73 | return max
74 | }
75 | }
76 |
77 | fun main() {
78 | val res = Easy_53_MaxSubArray.maxSubArray(intArrayOf(-2,1,-3,4,-1,2,1,-5,4))
79 | asserts(res, 6)
80 | val res1 = Easy_53_MaxSubArray.maxSubArray(intArrayOf(4,-1,2,1))
81 | asserts(res1, 6)
82 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/dp/subsequence/Med_1035_UncrossedLines.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.dp.subsequence
2 |
3 | import com.boycoder.utils.asserts
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/17
8 | * @desc: https://leetcode-cn.com/problems/uncrossed-lines/
9 | * This is similar to [Med_1143_LongestCommonSubsequence]
10 | * DP + DFS
11 | */
12 | object Med_1035_UncrossedLines {
13 | fun maxUncrossedLines(nums1: IntArray, nums2: IntArray): Int {
14 | return dp(nums1, nums2)
15 | }
16 |
17 | /**
18 | * dp
19 | *
20 | * dp[i][j] means nums1[0, i -1], nums2[0, j - 1] LCS size
21 | */
22 | private fun dp(nums1: IntArray, nums2: IntArray): Int {
23 | val size1 = nums1.size
24 | val size2 = nums2.size
25 |
26 | // dp array + init
27 | val dp = Array(size1 + 1){IntArray(size2 + 1) { 0 } }
28 |
29 | for (i in 1..size1) {
30 | for (j in 1..size2) {
31 | if (nums1[i - 1] == nums2[j - 1]) {
32 | dp[i][j] = dp[i - 1][j - 1] + 1
33 | } else {
34 | dp[i][j] = Math.max(dp[i][j - 1], dp[i - 1][j])
35 | }
36 | }
37 | }
38 |
39 | return dp[size1][size2]
40 | }
41 | }
42 |
43 | fun main() {
44 | val res = Med_1035_UncrossedLines.maxUncrossedLines(intArrayOf(1, 4, 2), intArrayOf(1, 2, 4))
45 | asserts(res, 2)
46 | val res1 = Med_1035_UncrossedLines.maxUncrossedLines(intArrayOf(2,5,1,2,5), intArrayOf(10,5,2,1,5,2))
47 | asserts(res1, 3)
48 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/dp/subsequence/Med_300_LongestIncreasingSubsequence.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.dp.subsequence
2 |
3 | import com.boycoder.utils.asserts
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/16
8 | * @desc: https://leetcode-cn.com/problems/longest-increasing-subsequence/
9 | */
10 | object Med_300_LongestIncreasingSubsequence {
11 | /**
12 | * dp
13 | *
14 | * dp[i] means [0, i] array LIS size
15 | * Try to break this problem into smaller problems
16 | */
17 | fun find(array: IntArray): Int {
18 | // init default value as 1
19 | val dp = IntArray(array.size) { 1 }
20 | for (i in 1 until array.size) {
21 | for (j in 0 until i) {
22 | if (array[i] > array[j]) {
23 | // dp[i] default value is 1
24 | dp[i] = Math.max(dp[i], dp[j] + 1)
25 | }
26 | }
27 | }
28 |
29 | return dp[array.size - 1]
30 | }
31 | }
32 |
33 | fun main() {
34 | val res = Med_300_LongestIncreasingSubsequence.find(intArrayOf(10,9,2,5,3,7,101,18))
35 | asserts(res, 4)
36 | val res1 = Med_300_LongestIncreasingSubsequence.find(intArrayOf(0,1,0,3,2,3))
37 | asserts(res1, 4)
38 | val res2 = Med_300_LongestIncreasingSubsequence.find(intArrayOf(7,7,7,7,7,7,7))
39 | asserts(res2, 1)
40 | }
41 |
--------------------------------------------------------------------------------
/src/com/boycoder/problems/dp/subsequence/Med_674_LongestIncreasingSubsequenceII.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.dp.subsequence
2 |
3 | import com.boycoder.utils.asserts
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/16
8 | * @desc: https://leetcode-cn.com/problems/longest-continuous-increasing-subsequence/
9 | *
10 | */
11 | object Med_674_LongestIncreasingSubsequenceII {
12 |
13 | fun longestSize(array: IntArray): Int {
14 | return find1(array)
15 | }
16 |
17 |
18 | /**
19 | * dp
20 | *
21 | * This problem can be break into smaller problems.
22 | * dp[i] means, the size of LIS that end with array[i]
23 | * if (array[i + 1] > array[i]) dp[i + 1] = dp[i] + 1
24 | *
25 | * For the longest subsequence could end with any index
26 | * so we need to store the max value of dp[i]
27 | */
28 | private fun find(array: IntArray): Int {
29 | // init every dp with 1
30 | val dp = IntArray(array.size) { 1 }
31 |
32 | var max = 1
33 |
34 | for (i in 1 until array.size) {
35 | if (array[i] > array[i - 1]) {
36 | dp[i] = dp[i - 1] + 1
37 | }
38 |
39 | max = Math.max(max, dp[i])
40 | }
41 |
42 | return max
43 | }
44 |
45 | /**
46 | * Greedy
47 | *
48 | * Use a loop go through the array.
49 | * count = 1
50 | * count = if (array[i] > array[i - 1]) count++ else 1
51 | * mark the max value
52 | */
53 | private fun find1(array: IntArray): Int {
54 | var count = 1
55 | var max = 1
56 |
57 | for (i in 1 until array.size) {
58 | if (array[i] > array[i - 1]) {
59 | count++
60 | } else {
61 | count = 1
62 | }
63 |
64 | max = Math.max(count, max)
65 | }
66 |
67 | return max
68 | }
69 |
70 | /**
71 | * Brute Force + pruning
72 | * We assume the longest subsequence should start from i
73 | * And we loop j [i + 1, size), if (array[i] > array[i - 1]) count++ else break
74 | */
75 | private fun find2(array: IntArray): Int {
76 | var max = 0
77 |
78 | for (i in 0 until array.size) {
79 | var count = 1
80 | for (j in i + 1 until array.size) {
81 | if (array[j] > array[j - 1]) {
82 | count++
83 | } else {
84 | break
85 | }
86 | }
87 | max = Math.max(count, max)
88 | }
89 | return max
90 | }
91 | }
92 |
93 | fun main() {
94 | val res = Med_674_LongestIncreasingSubsequenceII.longestSize(intArrayOf(1, 3, 5, 4, 7))
95 | asserts(res, 3)
96 | val res1 = Med_674_LongestIncreasingSubsequenceII.longestSize(intArrayOf(2, 2, 2, 2, 2))
97 | asserts(res1, 1)
98 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/dp/subsequence/Med_718_LongestSubArray.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.dp.subsequence
2 |
3 | import com.boycoder.utils.asserts
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/16
8 | * @desc: https://leetcode-cn.com/problems/maximum-length-of-repeated-subarray/
9 | * dfs + dp
10 | */
11 | object Med_718_LongestSubArray {
12 |
13 | fun longestSize(array1: IntArray, array2: IntArray): Int {
14 | return find1(array1, array2)
15 | }
16 |
17 | private fun find1(array1: IntArray, array2: IntArray): Int {
18 | val dp = Array(array1.size) {IntArray(array2.size) { 0 } }
19 | var max = 0
20 |
21 | // init when i = 0
22 | for (j in 0 until array2.size) {
23 | if (array2[j] == array1[0]) {
24 | dp[0][j] = 1
25 | }
26 | }
27 |
28 | // init when j = 0
29 | for (i in 0 until array1.size) {
30 | if (array1[i] == array2[0]) {
31 | dp[i][0] = 1
32 | }
33 | }
34 |
35 | for (i in 1 until array1.size) {
36 | for (j in 1 until array2.size) {
37 | if (array1[i] == array2[j]) {
38 | dp[i][j] = dp[i - 1][j - 1] + 1
39 | }
40 | max = Math.max(max, dp[i][j])
41 | }
42 | }
43 |
44 | return max
45 | }
46 |
47 |
48 | /**
49 | * dp
50 | *
51 | * dp[i][j] means array1[0, i - 1] and array2[0, j - 1] longest size
52 | */
53 | private fun find(array1: IntArray, array2: IntArray): Int {
54 | val dp = Array(array1.size + 1) { IntArray(array2.size + 1) { 0 } }
55 | var max = 0
56 |
57 | for (i in 1..array1.size) {
58 | for (j in 1..array2.size) {
59 | if (array1[i - 1] == array2[j - 1]) {
60 | dp[i][j] = dp[i - 1][j - 1] + 1
61 | }
62 |
63 | max = Math.max(max, dp[i][j])
64 | }
65 | }
66 |
67 | return max
68 | }
69 |
70 | }
71 |
72 | fun main() {
73 | val res = Med_718_LongestSubArray.longestSize(intArrayOf(1, 2, 3, 2, 1), intArrayOf(3, 2, 1, 4, 7))
74 | asserts(res, 3)
75 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/greedy/Easy_445_AssignCookie.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.greedy
2 |
3 | /**
4 | * @Author: zhutao
5 | * @datetime: 2021/6/4
6 | * @desc:
7 | */
8 | object Easy_445_AssignCookie {
9 |
10 | fun findContentChildren(g: IntArray, s: IntArray): Int {
11 | g.sort()
12 | s.sort()
13 | var i = g.size - 1
14 | var j = s.size - 1
15 |
16 | while (i >= 0 && j >= 0) {
17 | if (g[i] <= s[j]) {
18 | i--
19 | j--
20 | } else {
21 | i--
22 | }
23 | }
24 | return s.size - 1 - j
25 | }
26 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/hash/Easy_001_TwoSum.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.hash
2 |
3 | /**
4 | * @Author: zhutao
5 | * @datetime: 2021/6/4
6 | * @desc:
7 | */
8 | object Easy_001_TwoSum {
9 | fun twoSum(nums: IntArray, target: Int): IntArray {
10 | val map = mutableMapOf()
11 |
12 | nums.forEachIndexed { index, value ->
13 | if (map.contains(target - value)) {
14 | return intArrayOf(map[target - value]!!, index)
15 | }
16 | map.put(value, index)
17 | }
18 | return intArrayOf()
19 | }
20 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/hash/Easy_202_HappyNumber.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.hash
2 |
3 | /**
4 | * @Author: zhutao
5 | * @datetime: 2021/6/22
6 | * @desc: https://leetcode-cn.com/problems/happy-number/
7 | */
8 | object Easy_202_HappyNumber {
9 | fun isHappy(n: Int): Boolean {
10 | if (n < 0) return false
11 |
12 | val set = mutableSetOf()
13 | return check(n, set)
14 | }
15 |
16 | // tail recursion
17 | private fun check(n: Int, set: MutableSet): Boolean {
18 | if (n == 1) return true
19 | if (set.contains(n)) return false
20 | set.add(n)
21 |
22 | var sum = 0
23 | var num = n
24 | val digits = ArrayList()
25 |
26 | while (num > 0) {
27 | digits.add(num % 10)
28 | num = num / 10
29 | }
30 |
31 | var newNum = 0
32 | digits.forEach {
33 | newNum = it * it + newNum
34 | }
35 |
36 | return check(newNum, set)
37 | }
38 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/hash/Easy_242_Anagram.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.hash
2 |
3 | /**
4 | * @Author: zhutao
5 | * @datetime: 2021/6/22
6 | * @desc: https://leetcode-cn.com/problems/valid-anagram/
7 | */
8 | object Easy_242_Anagram {
9 | fun isAnagram(s: String, t: String): Boolean {
10 | val array1 = s.toCharArray()
11 | val array2 = t.toCharArray()
12 |
13 | val result = IntArray(26)
14 |
15 | for (char in array1) {
16 | result[char - 'a']++
17 | }
18 |
19 | for (char in array2) {
20 | result[char - 'a']--
21 | }
22 |
23 | return !result.any { it != 0 }
24 | }
25 |
26 | fun isAnagram1(s: String, t: String): Boolean {
27 | val map: MutableMap = mutableMapOf()
28 |
29 | s.toList().forEach{
30 | map.put(it, map.getOrDefault(it, 0) + 1)
31 | }
32 | t.toList().forEach {
33 | map.put(it, map.getOrDefault(it, 0) - 1)
34 | }
35 |
36 | return !map.values.any { it != 0 }
37 | }
38 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/hash/Easy_349_IntersectionTwoArray.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.hash
2 |
3 | /**
4 | * @Author: zhutao
5 | * @datetime: 2021/6/22
6 | * @desc: https://leetcode-cn.com/problems/intersection-of-two-arrays/
7 | */
8 | object Easy_349_IntersectionTwoArray {
9 | fun intersection(nums1: IntArray, nums2: IntArray): IntArray {
10 | val set1 = mutableSetOf()
11 | val set2 = mutableSetOf()
12 | val result = ArrayList()
13 |
14 | for (i in nums1) {
15 | set1.add(i)
16 | }
17 |
18 | for (j in nums2) {
19 | set2.add(j)
20 | }
21 |
22 | set1.forEach {
23 | if (set2.contains(it)) {
24 | result.add(it)
25 | }
26 | }
27 |
28 | return result.toIntArray()
29 | }
30 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/hash/Med_15_3Sum.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.hash
2 |
3 | /**
4 | * @Author: zhutao
5 | * @datetime: 2021/6/22
6 | * @desc: https://leetcode-cn.com/problems/3sum/
7 | */
8 | object Med_15_3Sum {
9 | fun threeSum(nums: IntArray): List> {
10 | nums.sort()
11 |
12 | var i = 0
13 | val list: MutableList> = mutableListOf()
14 |
15 | while (i < nums.size) {
16 | if (nums[i] > 0) return list
17 | var left = i + 1
18 | var right = nums.size - 1
19 |
20 | while (left < right) {
21 | if (nums[i] + nums[left] + nums[right] == 0) {
22 | list.add(listOf(nums[i], nums[left], nums[right]))
23 | while (left < right && nums[right] == nums.getOrNull(right - 1)) {
24 | right--
25 | }
26 | while (left < right && nums[left] == nums.getOrNull(left + 1)) {
27 | left++
28 | }
29 | left++
30 | right--
31 | } else if (nums[i] + nums[left] + nums[right] > 0) {
32 | while (left < right && nums[right] == nums.getOrNull(right - 1)) {
33 | right--
34 | }
35 | right--
36 | } else if (nums[i] + nums[left] + nums[right] < 0) {
37 | while (left < right && nums[left] == nums.getOrNull(left + 1)) {
38 | left++
39 | }
40 | left++
41 | }
42 | }
43 |
44 | while (nums[i] == nums.getOrNull(i + 1)) {
45 | i++
46 | }
47 |
48 | i++
49 | }
50 |
51 | return list
52 | }
53 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/hash/Med_18_4Sum.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.hash
2 |
3 | /**
4 | * @Author: zhutao
5 | * @datetime: 2021/6/22
6 | * @desc: https://leetcode-cn.com/problems/4sum/
7 | */
8 | object Med_18_4Sum {
9 | fun fourSum(nums: IntArray, target: Int): List> {
10 | nums.sort()
11 | val list: MutableList> = mutableListOf()
12 |
13 | var i = 0
14 | var j = 0
15 | while (i < nums.size) {
16 | j = i + 1
17 | while (j < nums.size - 1) {
18 |
19 | var left = j + 1
20 | var right = nums.size -1
21 | while (left < right) {
22 | val sum = nums[i] + nums[j] + nums[left] + nums[right]
23 |
24 | if (sum > target) {
25 | while (left < right && nums[right] == nums[right - 1]) {
26 | right--
27 | }
28 | right--
29 | } else if (sum < target) {
30 | while (left < right && nums[left] == nums[left + 1]) {
31 | left++
32 | }
33 | left++
34 | } else {
35 | list.add(listOf(nums[i], nums[j], nums[left], nums[right]))
36 | while (left < right && nums[right] == nums[right - 1]) {
37 | right--
38 | }
39 | right--
40 |
41 | while (left < right && nums[left] == nums[left + 1]) {
42 | left++
43 | }
44 | left++
45 | }
46 | }
47 | while (j < nums.size - 1 && nums[j] == nums[j + 1]) {
48 | j++
49 | }
50 | j++
51 |
52 | }
53 | while (i < nums.size - 1 && nums[i] == nums[i + 1]) {
54 | i++
55 | }
56 | i++
57 | }
58 | return list
59 | }
60 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/hash/Med_383_RansomNote.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.hash
2 |
3 | /**
4 | * @Author: zhutao
5 | * @datetime: 2021/6/22
6 | * @desc: https://leetcode-cn.com/problems/ransom-note/
7 | */
8 | object Med_383_RansomNote {
9 | fun canConstruct(ransomNote: String, magazine: String): Boolean {
10 | val array1 = IntArray(26)
11 | val array2 = IntArray(26)
12 |
13 | for (char in magazine.toCharArray()) {
14 | array1[char - 'a']++
15 | }
16 |
17 | for (char in ransomNote.toCharArray()) {
18 | array1[char - 'a']--
19 | }
20 |
21 | return !array1.any { it < 0 }
22 |
23 | }
24 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/hash/Med_454_FourSum.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.hash
2 |
3 | /**
4 | * @Author: zhutao
5 | * @datetime: 2021/6/22
6 | * @desc:
7 | */
8 | object Med_454_FourSum {
9 | fun fourSumCount(nums1: IntArray, nums2: IntArray, nums3: IntArray, nums4: IntArray): Int {
10 | val map1 = hashMapOf()
11 | var res = 0
12 |
13 |
14 | for (i in nums1) {
15 | for (j in nums2) {
16 | map1.put(i + j, map1.getOrDefault(i + j, 0) + 1)
17 | }
18 | }
19 |
20 | for (i in nums3) {
21 | for (j in nums4) {
22 | if (map1.contains(-i -j)) {
23 | res = res + map1[-i-j]!!
24 | }
25 | }
26 | }
27 |
28 | return res
29 | }
30 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/linkedList/Easy_203_RemoveLinkedListElements.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.linkedList
2 |
3 | import com.boycoder.basis.datastructure.ListNode
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/4
8 | * @desc:
9 | */
10 | object Easy_203_RemoveLinkedListElements {
11 |
12 | fun removeElements(head: ListNode?, target: Int): ListNode? {
13 | if (head == null) return head
14 | val dummy = ListNode(-1, head)
15 |
16 | var slow: ListNode? = dummy
17 | var fast: ListNode? = head
18 | while (fast != null && slow != null) {
19 | if (fast.value == target) {
20 | slow.next = fast.next
21 | fast = fast.next
22 | } else {
23 | slow = fast
24 | fast = fast.next
25 | }
26 | }
27 |
28 | return dummy.next
29 | }
30 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/linkedList/Easy_206_ReverseLinkedList.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.linkedList
2 |
3 | import com.boycoder.basis.datastructure.ListNode
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/22
8 | * @desc: https://leetcode-cn.com/problems/reverse-linked-list/
9 | */
10 | object Easy_206_ReverseLinkedList {
11 | fun reverseList(head: ListNode?): ListNode? {
12 | if (head == null) return head
13 | return reverseRecur(head)
14 | }
15 |
16 | fun reverseRecur(head: ListNode): ListNode? {
17 | if (head.next == null) return head
18 |
19 | var result = reverseRecur(head.next!!)
20 |
21 | var next = head.next!!
22 | next.next = head
23 | head.next = null
24 | return result
25 | }
26 |
27 | /**
28 | * Ideal
29 | *1. Two pointer
30 | *
31 | * 1 -> 2 -> 3 -> 4 -> 5 -> null
32 | *
33 | * null <- 1 -> 2 -> 3 -> 4 -> 5 -> null
34 | */
35 | fun reverseList1(head: ListNode?): ListNode? {
36 | if (head == null) return head
37 |
38 | var pre: ListNode? = null
39 | var cur = head
40 | var next: ListNode? = null
41 |
42 | while (cur != null) {
43 | next = cur.next
44 | cur.next = pre
45 | pre = cur
46 | cur = next
47 | }
48 |
49 | return pre
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/com/boycoder/problems/linkedList/Med_19_RemoveNthFromEnd.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.linkedList
2 |
3 | import com.boycoder.basis.datastructure.ListNode
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/22
8 | * @desc:
9 | */
10 | object Med_19_RemoveNthFromEnd {
11 | fun removeNthFromEnd(head: ListNode?, n: Int): ListNode? {
12 | var dummy = ListNode(0, head)
13 |
14 | var right = dummy
15 | var left = dummy
16 |
17 | // let right pointer go faster
18 | var step = n
19 | while (step > 0) {
20 | right = right.next!!
21 | step--
22 | }
23 |
24 | // then let right pointer go to the end
25 | while (right.next != null) {
26 | right = right.next!!
27 | left = left.next!!
28 | }
29 |
30 | // delete the Nth node
31 | left.next = left.next!!.next
32 |
33 | return dummy.next
34 | }
35 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/linkedList/Med_24_SwapNodeInPair.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.linkedList
2 |
3 | import com.boycoder.basis.datastructure.ListNode
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/22
8 | * @desc: https://leetcode-cn.com/problems/swap-nodes-in-pairs/
9 | */
10 | object Med_24_SwapNodeInPair {
11 | fun swapPairs(head: ListNode?): ListNode? {
12 | if (head == null || head.next == null) return head
13 |
14 | var dummy = ListNode(0, head)
15 | var pre = dummy
16 | var cur = head
17 |
18 | while (cur != null && cur.next != null) {
19 |
20 | val next = cur.next!!
21 | val nextCur = next.next
22 |
23 | pre.next = next
24 | next.next = cur
25 | cur.next = nextCur
26 |
27 | pre = cur
28 | cur = nextCur
29 | }
30 |
31 | return dummy.next
32 | }
33 | }
34 |
35 |
--------------------------------------------------------------------------------
/src/com/boycoder/problems/monotone/Easy_155_MinStack.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.monotone
2 |
3 | /**
4 | * @Author: zhutao
5 | * @datetime: 2021/6/22
6 | * @desc:
7 | */
8 | class Easy_155_MinStack {
9 |
10 | /** initialize your data structure here. */
11 | val array = mutableListOf()
12 | val minArray = mutableListOf()
13 |
14 | fun push(x: Int) {
15 | array.add(x)
16 | val top = minArray.getOrNull(minArray.size - 1)?: Int.MAX_VALUE
17 | val min = Math.min(top, x)
18 | minArray.add(min)
19 | }
20 |
21 | fun pop() {
22 | array.removeAt(array.size - 1)
23 | minArray.removeAt(minArray.size - 1)
24 | }
25 |
26 | fun top(): Int {
27 | return array.get(array.size - 1)
28 | }
29 |
30 | fun getMin(): Int {
31 | return minArray.get(minArray.size - 1)
32 | }
33 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/monotone/Hard_42_TrapRainWater.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.monotone
2 |
3 | import com.boycoder.utils.asserts
4 | import java.util.*
5 |
6 | /**
7 | * @Author: zhutao
8 | * @datetime: 2021/6/22
9 | * @desc:
10 | */
11 | object Hard_42_TrapRainWater {
12 | private var array = intArrayOf()
13 | fun trap(height: IntArray): Int {
14 | array = height
15 | return count1()
16 | }
17 |
18 | /**
19 | * Monotone stack
20 | */
21 | private fun count1(): Int {
22 | var sum = 0
23 | // put index
24 | val stk = LinkedList()
25 |
26 | for (i in 0 until array.size) {
27 | while (!stk.isEmpty() && array[stk.getLast()] < array[i]) {
28 | val cur = stk.removeLast()
29 | if (stk.isEmpty()) break
30 |
31 | val left = stk.getLast()
32 | val right = i
33 | val low = Math.min(array[left], array[right])
34 | if (low > array[cur]) {
35 | sum = sum + (right - left - 1) * (low - array[cur])
36 | }
37 | }
38 | stk.addLast(i)
39 | }
40 |
41 | return sum
42 | }
43 |
44 | /**
45 | * Brute Force
46 | *
47 | * Count every col of water and then sum then up.
48 | */
49 | fun count(): Int {
50 | var sum = 0
51 |
52 | for (i in 0 until array.size) {
53 | if (i == 0 || i == array.size - 1) {
54 | continue
55 | }
56 |
57 | // highest index to the left and right
58 | var left = i
59 | var right = i
60 |
61 | // here can be optimized by dp
62 | for (j in i - 1 downTo 0) {
63 | if (array[j] > array[left]) {
64 | left = j
65 | }
66 | }
67 |
68 | // here can be optimized by dp
69 | for (k in i + 1 until array.size) {
70 | if (array[k] > array[right]) {
71 | right = k
72 | }
73 | }
74 |
75 | val low = Math.min(array[left], array[right])
76 |
77 | if (low > array[i]) {
78 | sum = sum + (low - array[i])
79 | }
80 | }
81 |
82 | return sum
83 | }
84 | }
85 |
86 | fun main() {
87 | val res = Hard_42_TrapRainWater.trap(intArrayOf(0,1,0,2,1,0,1,3,2,1,2,1))
88 | asserts(res, 6)
89 | val res1 = Hard_42_TrapRainWater.trap(intArrayOf(4,2,0,3,2,5))
90 | asserts(res1, 9)
91 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/monotone/Med_1438_LongestSubArrayLimitedAbs.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.monotone
2 |
3 | import java.util.*
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/22
8 | * @desc:
9 | */
10 | object Med_1438_LongestSubArrayLimitedAbs {
11 | fun longestSubarray(nums: IntArray, limit: Int): Int {
12 | // 4, 3, 2, 1
13 | val maxQueue = LinkedList()
14 | // 1, 2, 3, 4
15 | val minQueue = LinkedList()
16 | val len = nums.size
17 | var left = 0
18 | var right = 0
19 | var max = 0
20 |
21 | while (right < len) {
22 | while (!maxQueue.isEmpty() && maxQueue.getLast() < nums[right]) {
23 | maxQueue.removeLast()
24 | }
25 |
26 | while (!minQueue.isEmpty() && minQueue.getLast() > nums[right]) {
27 | minQueue.removeLast()
28 | }
29 |
30 | maxQueue.addLast(nums[right])
31 | minQueue.addLast(nums[right])
32 |
33 | while (maxQueue.getFirst() - minQueue.getFirst() > limit) {
34 | if (maxQueue.getFirst() == nums[left]) maxQueue.removeFirst()
35 | if (minQueue.getFirst() == nums[left]) minQueue.removeFirst()
36 | left++
37 | }
38 |
39 | max = Math.max(max, right - left + 1)
40 | right++
41 | }
42 |
43 | return max
44 | }
45 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/monotone/Med_739_DailyTemperatures.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.monotone
2 |
3 | import com.boycoder.utils.assertCollection
4 | import java.util.*
5 |
6 | /**
7 | * @Author: zhutao
8 | * @datetime: 2021/6/22
9 | * @desc:
10 | */
11 | object Med_739_DailyTemperatures {
12 | private var array = intArrayOf()
13 |
14 | fun dailyTemperatures(temperatures: IntArray): IntArray {
15 | array = temperatures
16 | return find1()
17 | }
18 |
19 | /**
20 | * Brute Force
21 | */
22 | private fun find(): IntArray {
23 | val res = IntArray(array.size)
24 |
25 | // calculate every index
26 | for (i in 0 until array.size) {
27 | for (j in i + 1 until array.size) {
28 | if (array[j] > array[i]) {
29 | res[i] = j - i
30 | break
31 | }
32 | }
33 | }
34 |
35 | return res
36 | }
37 |
38 | private fun find1(): IntArray {
39 | val res = IntArray(array.size)
40 | // 4, 3, 3, 2, 1
41 | val stk = ArrayDeque()
42 |
43 | for (i in 0 until array.size) {
44 | while (!stk.isEmpty() && array[stk.getLast()] < array[i]) {
45 | val index = stk.removeLast()
46 | res[index] = i - index
47 | }
48 |
49 | stk.addLast(i)
50 | }
51 |
52 | return res
53 | }
54 | }
55 |
56 | fun main() {
57 | val res = Med_739_DailyTemperatures.dailyTemperatures(intArrayOf(73, 74, 75, 71, 69, 72, 76, 73))
58 | assertCollection(res.asList(), intArrayOf(1, 1, 4, 2, 1, 1, 0, 0).asList())
59 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/monotone/Med_MaxQueue.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.monotone
2 |
3 | /**
4 | * @Author: zhutao
5 | * @datetime: 2021/6/22
6 | * @desc: https://leetcode-cn.com/problems/dui-lie-de-zui-da-zhi-lcof/
7 | *
8 | * This data structure should work as a normal queue,
9 | * and it can get the max value O(n)
10 | *
11 | * So, we should use a normal queue to hold the elements.
12 | * and another data structure to hold the max elements.
13 | */
14 | class Med_MaxQueue() {
15 |
16 | private var queue: ArrayDeque
17 | private var max: ArrayDeque
18 |
19 | init {
20 | queue = ArrayDeque()
21 | max = ArrayDeque()
22 | }
23 |
24 | /**
25 | * get max
26 | */
27 | fun max_value(): Int {
28 | if (max.size == 0) {
29 | return -1
30 | }
31 |
32 | return max.first()
33 | }
34 |
35 | /**
36 | * add last
37 | */
38 | fun push_back(value: Int) {
39 | queue.addLast(value)
40 |
41 | if (max.size == 0) {
42 | max.addLast(value)
43 | return
44 | }
45 |
46 | // maintain the max queue
47 | // 4 2 1 add 3
48 | // 4 add 3
49 | while (max.size > 0 && max.last() < value) {
50 | max.removeLast()
51 | }
52 |
53 | max.addLast(value)
54 | }
55 |
56 | /**
57 | * remove first
58 | */
59 | fun pop_front(): Int {
60 | if (queue.size == 0) {
61 | return -1
62 | }
63 |
64 | val res = queue.removeFirst()
65 | if (res == max.first()) {
66 | max.removeFirst()
67 | }
68 |
69 | return res
70 | }
71 | }
72 |
73 | fun main() {
74 | val queue = Med_MaxQueue()
75 | queue.push_back(1)
76 | queue.push_back(2)
77 | println(queue.max_value())
78 | queue.pop_front()
79 | println(queue.max_value())
80 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/pointers/Easy_35_SearchInsertPosition.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.pointers
2 |
3 | import com.boycoder.utils.asserts
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/21
8 | * @desc:
9 | */
10 | object Easy_35_SearchInsertPosition {
11 |
12 | /**
13 | * 1, 3, 5, 6
14 | * | |
15 | *
16 | * 1, 3, 5, 6
17 | * | |
18 | *
19 | * 1, 3, 5, 6
20 | * | |
21 | * 1, 3, 5, 6
22 | * | |
23 | */
24 | fun searchInsert(nums: IntArray, target: Int): Int {
25 | var left = 0
26 | var right = nums.size - 1
27 |
28 | while (left <= right) {
29 | val mid = (right + left) /2
30 | if (target > nums[mid]) {
31 | left = mid + 1
32 | } else if (target < nums[mid]) {
33 | right = mid - 1
34 | } else {
35 | return mid
36 | }
37 | }
38 |
39 | return left
40 | }
41 | }
42 |
43 | fun main() {
44 | val res = Easy_35_SearchInsertPosition.searchInsert(intArrayOf(1,3,5,6), 5)
45 | asserts(res, 2)
46 | val res1 = Easy_35_SearchInsertPosition.searchInsert(intArrayOf(1,3,5,6), 2)
47 | asserts(res1, 1)
48 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/stack/Easy_1047_RemoveDuplicate.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.stack
2 |
3 | /**
4 | * @Author: zhutao
5 | * @datetime: 2021/6/22
6 | * @desc:
7 | */
8 | object Easy_1047_RemoveDuplicate {
9 | fun removeDuplicates(s: String): String {
10 | val stk = ArrayDeque()
11 | val array = s.toCharArray()
12 |
13 | for (char in array) {
14 | if (stk.isEmpty()) {
15 | stk.addLast(char)
16 | } else if (stk.last() == char) {
17 | stk.removeLast()
18 | } else if (stk.last() != char) {
19 | stk.addLast(char)
20 | }
21 | }
22 |
23 | return stk.joinToString("")
24 | }
25 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/stack/Easy_20_ValidParentheses.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.stack
2 |
3 | import com.boycoder.utils.asserts
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/4
8 | * @desc:
9 | */
10 | object Easy_20_ValidParentheses {
11 | fun isValid(s: String): Boolean {
12 | val stk = ArrayDeque()
13 | val array = s.toCharArray()
14 |
15 | for (char in array) {
16 | if (isLeft(char)) {
17 | stk.addLast(char)
18 | } else {
19 | if (stk.isEmpty()) return false
20 |
21 | if (!isMatching(stk.removeLast(), char)) {
22 | return false
23 | }
24 | }
25 | }
26 |
27 | return stk.isEmpty()
28 | }
29 |
30 | private fun isMatching(left: Char, right: Char): Boolean {
31 | return when (left) {
32 | '(' -> right == ')'
33 | '[' -> right == ']'
34 | '{' -> right == '}'
35 | else -> false
36 | }
37 | }
38 |
39 | private fun isLeft(char: Char): Boolean {
40 | return when(char) {
41 | '(' -> true
42 | '[' -> true
43 | '{' -> true
44 | else -> false
45 | }
46 | }
47 | }
48 |
49 | fun main() {
50 | val s = "()[]{}"
51 | val res = Easy_20_ValidParentheses.isValid(s)
52 | val res1 = Easy_20_ValidParentheses.isValid("([)]")
53 | val res2 = Easy_20_ValidParentheses.isValid("{[]}")
54 | asserts(res, true)
55 | asserts(res1, false)
56 | asserts(res2, true)
57 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/stack/Easy_225_ImpStackUseQueue.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.stack
2 |
3 | import java.util.*
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/22
8 | * @desc:
9 | */
10 | object Easy_225_ImpStackUseQueue {
11 |
12 | /** Initialize your data structure here. */
13 | val queue = LinkedList()
14 | val backup = LinkedList()
15 |
16 | /** Push element x onto stack. */
17 | fun push(x: Int) {
18 | queue.addLast(x)
19 | }
20 |
21 | /** Removes the element on top of the stack and returns that element. */
22 | fun pop(): Int {
23 | return popByType(true)
24 | }
25 |
26 | private fun popByType(isOut: Boolean): Int {
27 | var value = 0
28 | while (!queue.isEmpty()) {
29 | if (queue.size == 1) {
30 | value = queue.removeFirst()
31 | if (!isOut) {
32 | backup.addLast(value)
33 | }
34 | } else {
35 | backup.addLast(queue.removeFirst())
36 | }
37 | }
38 |
39 | while (!backup.isEmpty()) {
40 | queue.addLast(backup.removeFirst())
41 | }
42 |
43 | return value
44 | }
45 |
46 | /** Get the top element. */
47 | fun top(): Int {
48 | return popByType(false)
49 | }
50 |
51 | /** Returns whether the stack is empty. */
52 | fun empty(): Boolean {
53 | return queue.isEmpty() && backup.isEmpty()
54 | }
55 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/stack/Easy_232_ImpQueueUseStack.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.stack
2 |
3 | /**
4 | * @Author: zhutao
5 | * @datetime: 2021/6/22
6 | * @desc:
7 | */
8 | object Easy_232_ImpQueueUseStack {
9 | /** Initialize your data structure here. */
10 | val outStk = ArrayDeque()
11 | val inStk = ArrayDeque()
12 |
13 | /** Push element x to the back of queue. */
14 | fun push(x: Int) {
15 | inStk.addLast(x)
16 | }
17 |
18 | /** Removes the element from in front of queue and returns that element. */
19 | fun pop(): Int {
20 | if (empty()) {
21 | return 0 // throw exception
22 | }
23 |
24 | // make sure in stack empty
25 | while (!inStk.isEmpty()) {
26 | outStk.addLast(inStk.removeLast())
27 | }
28 |
29 | return outStk.removeLast()
30 | }
31 |
32 | /** Get the front element. */
33 | fun peek(): Int {
34 | var value = pop()
35 | outStk.addLast(value)
36 |
37 | return value
38 | }
39 |
40 | /** Returns whether the queue is empty. */
41 | fun empty(): Boolean {
42 | return inStk.isEmpty() && outStk.isEmpty()
43 | }
44 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/stack/Hard_239_SlidingWindowMax.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.stack
2 |
3 | /**
4 | * @Author: zhutao
5 | * @datetime: 2021/6/22
6 | * @desc:
7 | */
8 | object Hard_239_SlidingWindowMax {
9 | fun maxSlidingWindow(nums: IntArray, k: Int): IntArray {
10 | val queue = MaxQueue()
11 | val list = mutableListOf()
12 |
13 | // fill the window with [0, k -1]
14 | for (i in 0 until k) {
15 | queue.addLast(nums[i])
16 | }
17 | list.add(queue.max())
18 |
19 | for (i in k until nums.size) {
20 | queue.removeIfMatch(nums[i - k])
21 | queue.addLast(nums[i])
22 |
23 | list.add(queue.max())
24 | }
25 |
26 | return list.toIntArray()
27 | }
28 |
29 | fun maxSlidingWindow1(nums: IntArray, k: Int): IntArray {
30 | val queue = MaxQueue()
31 | val list = mutableListOf()
32 |
33 | var left = 0
34 | for (right in 0 until nums.size) {
35 | queue.addLast(nums[right])
36 | if (right < k - 1) {
37 | continue
38 | }
39 |
40 | // window full
41 | if (right == k - 1) {
42 | list.add(queue.max())
43 | } else {
44 | // bigger
45 | val leftEdge = nums[right - k]
46 | if (leftEdge == queue.max()) {
47 | queue.removeFront()
48 | list.add(queue.max())
49 | } else {
50 | list.add(queue.max())
51 | }
52 | }
53 | }
54 |
55 | return list.toIntArray()
56 | }
57 | }
58 |
59 | /**
60 | This is a queue only keep the max value at the front
61 | 5, 5, 4, 3, 2
62 | */
63 | class MaxQueue {
64 | val queue = ArrayDeque()
65 |
66 | fun addLast(x: Int) {
67 | if (queue.isEmpty()) {
68 | queue.addLast(x)
69 | } else {
70 | while (!queue.isEmpty() && queue.last() < x) {
71 | queue.removeLast()
72 | }
73 | queue.addLast(x)
74 | }
75 | }
76 |
77 | fun removeFront(): Int {
78 | return queue.removeFirst()
79 | }
80 |
81 | fun removeIfMatch(x: Int) {
82 | if (!queue.isEmpty() && x == max()) {
83 | removeFront()
84 | }
85 | }
86 |
87 | fun max(): Int {
88 | return queue.first()
89 | }
90 |
91 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/stack/Med_150_ReversePolishNotation.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.stack
2 |
3 | /**
4 | * @Author: zhutao
5 | * @datetime: 2021/6/22
6 | * @desc:
7 | */
8 | object Med_150_ReversePolishNotation {
9 | fun evalRPN(tokens: Array): Int {
10 | val stk = ArrayDeque()
11 |
12 | for (s in tokens) {
13 | if (!isOprator(s)) {
14 | stk.addLast(s)
15 | } else {
16 | val res = calculate(stk.removeLast().toInt(), stk.removeLast().toInt(), s)
17 | stk.addLast(res.toString())
18 | }
19 | }
20 |
21 | return stk.removeLast().toInt()
22 | }
23 |
24 | private fun calculate(b: Int, a: Int, oprator: String): Int {
25 | return when (oprator) {
26 | "+" -> a + b
27 | "-" -> a - b
28 | "*" -> a * b
29 | "/" -> a / b
30 | else -> { 0 } // throw exception
31 | }
32 | }
33 |
34 | private fun isOprator(s: String): Boolean {
35 | return s == "+" || s == "-" || s == "*" || s == "/"
36 | }
37 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/stack/Med_347_TopKFrequentElements.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.stack
2 |
3 | import java.util.*
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/22
8 | * @desc:
9 | */
10 | object Med_347_TopKFrequentElements {
11 | fun topKFrequent(nums: IntArray, k: Int): IntArray {
12 | val map = hashMapOf()
13 | val heap = PriorityQueue>(k, {o1, o2 ->
14 | // sorted by value, and min heap
15 | o2.value - o1.value
16 | })
17 |
18 | for (i in nums) {
19 | map.put(i, map.getOrDefault(i, 0) + 1)
20 | }
21 |
22 | map.entries.forEach {
23 | heap.offer(it)
24 | }
25 |
26 | val array = IntArray(k)
27 | for (i in 0 until k) {
28 | array[i] = heap.poll().key
29 | }
30 |
31 | return array;
32 | }
33 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/string/Easy_28_ImplementStr.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.string
2 |
3 | /**
4 | * @Author: zhutao
5 | * @datetime: 2021/6/22
6 | * @desc:
7 | */
8 | object Easy_28_ImplementStr {
9 |
10 | /**
11 | * Implementation for the Rabin Karp in Kotlin
12 | *
13 | * "hello"
14 | * "ll" -> 'l' * 31 + 'l' * 31^0
15 | */
16 | fun strStr(s: String, pat: String): Int {
17 |
18 | // get the power of last digits
19 | // calculate the hash of pat
20 | // compare the hash
21 | val sLength = s.length
22 | val pLength = pat.length
23 | if (pLength == 0) {
24 | return 0
25 | }
26 | if (sLength < pLength) {
27 | return -1
28 | }
29 |
30 | var power = 1
31 | val mod = Math.pow(2.0, 20.0).toInt()
32 |
33 | for (i in 0 until pLength) {
34 | power = power * 31 % mod
35 | }
36 |
37 | var pHash = 0
38 | for (i in 0 until pLength) {
39 | pHash = (pHash * 31 + pat.get(i).toInt()) % mod
40 | }
41 |
42 | var sHash = 0
43 | for (j in 0 until sLength) {
44 |
45 | sHash = (sHash * 31 + s.get(j).toInt()) % mod
46 |
47 | if (j < pLength - 1) {
48 | continue
49 | }
50 |
51 | if (j >= pLength) {
52 | sHash = sHash - ((power * s.get(j - pLength).toInt()) % mod)
53 |
54 | if (sHash < 0) {
55 | sHash = sHash + mod
56 | }
57 | }
58 |
59 | if (sHash == pHash) {
60 | // double check
61 | if (s.substring(j - pLength + 1, j + 1).equals(pat)) {
62 | return j - pLength + 1
63 | }
64 | }
65 | }
66 | return -1
67 | }
68 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/string/Easy_344_ReverseString.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.string
2 |
3 | import com.boycoder.utils.asserts
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/4
8 | * @desc:
9 | */
10 | object Easy_344_ReverseString {
11 |
12 | fun reverse(array: CharArray) {
13 | if (array.isEmpty()) return
14 |
15 | var left = 0
16 | var right = array.size - 1
17 |
18 | while (left < right) {
19 | val temp = array[left]
20 | array[left] = array[right]
21 | array[right] = temp
22 | left++
23 | right--
24 | }
25 | }
26 | }
27 |
28 | fun main() {
29 | val array = charArrayOf('h', 'e', 'l', 'l', 'o')
30 | Easy_344_ReverseString.reverse(array)
31 |
32 | var res = true
33 | val array1 = charArrayOf('o', 'l', 'l', 'e', 'h')
34 | for (i in 0 until array.size) {
35 | if (array1[i] != array[i]) {
36 | res = false
37 | }
38 | }
39 |
40 | asserts(res, true)
41 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/string/Med_151_ReverseWordInString.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.string
2 |
3 | /**
4 | * @Author: zhutao
5 | * @datetime: 2021/6/22
6 | * @desc: https://leetcode-cn.com/problems/reverse-words-in-a-string/
7 | */
8 | object Med_151_ReverseWordInString {
9 | fun reverseWords(s: String): String {
10 | var string = s.trim()
11 |
12 | var array = string.toCharArray()
13 | // remove space
14 | var left = 0
15 | var right = 0
16 |
17 | while (left <= right && right < array.size) {
18 | if (array[right] != ' ') {
19 | array[left] = array[right]
20 | left++
21 | right++
22 | } else {
23 | while (array[right + 1] == ' ') {
24 | right++
25 | }
26 | array[left] = array[right]
27 | left++
28 | right++
29 | }
30 | }
31 | if (left < array.size) {
32 | array = array.slice(0..left-1).toCharArray()
33 | }
34 |
35 | // reverse the whole array
36 | reverse(array, 0, array.size - 1)
37 |
38 | left = 0
39 | right = 0
40 | while (right < array.size) {
41 | if (right == array.size - 1) {
42 | reverse(array, left, right)
43 | right++
44 | left = right
45 | } else if (array[right + 1] == ' ') {
46 | reverse(array, left, right)
47 | right = right + 2
48 | left = right
49 | } else {
50 | right++
51 | }
52 | }
53 |
54 | return array.joinToString("")
55 | }
56 |
57 | private fun reverse(array: CharArray, i: Int, j: Int) {
58 | var left = i
59 | var right = j
60 |
61 | while (left <= right) {
62 | val temp = array[left]
63 | array[left] = array[right]
64 | array[right] = temp
65 | left++
66 | right--
67 | }
68 | }
69 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/tree/Easy_101_SymmetricTree.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.tree
2 |
3 | import com.boycoder.basis.datastructure.TreeNode
4 | import java.util.*
5 |
6 | /**
7 | * @Author: zhutao
8 | * @datetime: 2021/6/22
9 | * @desc:
10 | */
11 | object Easy_101_SymmetricTree {
12 | fun isSymmetric(root: TreeNode?): Boolean {
13 | return isSym(root?.left, root?.right)
14 | }
15 |
16 | private fun isSym(node1: TreeNode?, node2: TreeNode?): Boolean {
17 | // case that need return
18 | if (node1 == null && node2 == null) {
19 | return true
20 | } else if (node1 != null && node2 == null) {
21 | return false
22 | } else if (node1 == null && node2 != null) {
23 | return false
24 | } else if (node1!!.value != node2!!.value) {
25 | return false
26 | } else {
27 | // node1 node2 not null then we need to compare with recursion
28 | val outSide = isSym(node1.left, node2.right)
29 | val inSide = isSym(node1.right, node2.left)
30 | return outSide && inSide
31 | }
32 | }
33 |
34 | private fun isSym1(root: TreeNode?): Boolean {
35 | if (root == null) return true
36 |
37 | val queue = LinkedList()
38 | queue.addLast(root)
39 |
40 | while (!queue.isEmpty()) {
41 | val size = queue.size
42 |
43 | val temps = mutableListOf()
44 | for (i in 0 until size) {
45 | val node = queue.removeFirst()
46 | if (node != null) {
47 | temps.add(node.left)
48 | temps.add(node.right)
49 |
50 | queue.addLast(node.left)
51 | queue.addLast(node.right)
52 | }
53 | }
54 |
55 | // for every level, we check the level Symmetric
56 | if (!isListSym(temps)) {
57 | return false
58 | }
59 | }
60 |
61 | return true
62 | }
63 |
64 | private fun isSame(node1: TreeNode?, node2: TreeNode?): Boolean {
65 | if (node1 == null && node2 == null) {
66 | return true
67 | } else if (node1 != null && node2 != null && node1.value == node2.value) {
68 | return true
69 | } else {
70 | return false
71 | }
72 | }
73 |
74 | private fun isListSym(list: List): Boolean {
75 | if (list.isEmpty()) return true
76 |
77 | var left = 0
78 | val size = list.size
79 | var right = size - 1
80 |
81 | while (left <= right) {
82 | if (!isSame(list[left], list[right])) {
83 | return false
84 | }
85 | left++
86 | right--
87 | }
88 |
89 | return true
90 | }
91 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/tree/Easy_104_MaxDepthBinaryTree.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.tree
2 |
3 | import com.boycoder.basis.datastructure.TreeNode
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/22
8 | * @desc:
9 | */
10 | object Easy_104_MaxDepthBinaryTree {
11 | fun maxDepth(root: TreeNode?): Int {
12 | return getDepth(root)
13 | }
14 |
15 | // level traversal
16 | private fun getDepth(root: TreeNode?): Int {
17 | if (root == null) return 0
18 |
19 | val queue = ArrayDeque()
20 | queue.addLast(root)
21 | var node: TreeNode? = null
22 | var depth = 0
23 |
24 | while (!queue.isEmpty()) {
25 | depth++
26 | val size = queue.size
27 | for (i in 0 until size) {
28 | node = queue.removeFirst()
29 | node.left?.let {
30 | queue.addLast(it)
31 | }
32 |
33 | node.right?.let {
34 | queue.addLast(it)
35 | }
36 | }
37 | }
38 | return depth
39 | }
40 |
41 | // recursion post order is preferred, pre order is not
42 | private fun getDepth1(root: TreeNode?): Int {
43 | if (root == null) return 0
44 |
45 | val left = getDepth(root.left)
46 | val right = getDepth(root.right)
47 |
48 | return 1 + Math.max(left, right)
49 | }
50 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/tree/Easy_110_BalancedBinaryTree.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.tree
2 |
3 | import com.boycoder.basis.datastructure.TreeNode
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/22
8 | * @desc:
9 | */
10 | object Easy_110_BalancedBinaryTree {
11 | fun isBalanced(root: TreeNode?): Boolean {
12 | val depth = getDepth(root)
13 | return depth != -1
14 | }
15 |
16 | /**
17 | * use recursion post order
18 | * count every left depth and right depth
19 | * check if abs(left - right) > 1, if so return -1, means not balanced
20 | */
21 | private fun getDepth(root: TreeNode?): Int {
22 | if (root == null) return 0
23 |
24 | val left = getDepth(root.left)
25 | val right = getDepth(root.right)
26 |
27 | if (left == -1 || right == -1) return -1
28 |
29 | if (Math.abs(left - right) > 1) return -1
30 |
31 | return Math.max(left, right) + 1
32 | }
33 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/tree/Easy_111_MinDepthBinaryTree.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.tree
2 |
3 | import com.boycoder.basis.datastructure.TreeNode
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/22
8 | * @desc:
9 | */
10 | object Easy_111_MinDepthBinaryTree {
11 | fun minDepth(root: TreeNode?): Int {
12 | if (root == null) return 0
13 | return getDepth(root)
14 | }
15 |
16 | /**
17 | * level traversal
18 | *
19 | * We count the depth from 0
20 | * and when we meet a leaf node, we stop the counting
21 | */
22 | private fun getDepth(root: TreeNode): Int {
23 | val queue = ArrayDeque()
24 | queue.add(root)
25 | var depth = 0
26 |
27 | while (!queue.isEmpty()) {
28 | val size = queue.size
29 | depth++
30 | for (i in 0 until size) {
31 | val node = queue.removeFirst()
32 | if (node.left == null && node.right == null) {
33 | return depth
34 | }
35 |
36 | if (node.left != null) queue.addLast(node.left!!)
37 | if (node.right != null) queue.addLast(node.right!!)
38 | }
39 | }
40 |
41 | return depth
42 | }
43 |
44 | /**
45 | * dfs
46 | *
47 | * can be optimized using cache
48 | */
49 | private fun getDepth1(root: TreeNode): Int {
50 | if (root.left == null && root.right == null){
51 | return 1
52 | } else if (root.left == null && root.right != null) {
53 | return getDepth(root.right!!) + 1
54 | } else if (root.left != null && root.right == null) {
55 | return getDepth(root.left!!) + 1
56 | } else {
57 | return Math.min(getDepth(root.left!!), getDepth(root.right!!)) + 1
58 | }
59 | }
60 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/tree/Easy_112_PathSum.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.tree
2 |
3 | import com.boycoder.basis.datastructure.TreeNode
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/22
8 | * @desc:
9 | */
10 | object Easy_112_PathSum {
11 | fun hasPathSum(root: TreeNode?, targetSum: Int): Boolean {
12 | if (root == null) return false
13 | return hasSum(root, targetSum)
14 | }
15 |
16 | private fun hasSum(root: TreeNode, targetSum: Int): Boolean {
17 | if (root.left == null && root.right == null) {
18 | return targetSum == root.value
19 | }
20 |
21 | var flag = false
22 | val target = targetSum - root.value
23 | if (root.left != null) {
24 | flag = flag or hasSum(root.left!!, target)
25 | }
26 |
27 | if (root.right != null) {
28 | flag = flag or hasSum(root.right!!, target)
29 | }
30 | return flag
31 | }
32 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/tree/Easy_144_BinaryTreePreorder.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.tree
2 |
3 | import com.boycoder.basis.datastructure.TreeNode
4 | import java.util.*
5 | import kotlin.collections.ArrayDeque
6 |
7 | /**
8 | * @Author: zhutao
9 | * @datetime: 2021/6/4
10 | * @desc:
11 | */
12 | object Easy_144_BinaryTreePreorder {
13 | fun preorderTraversal(root: TreeNode?): List {
14 | val list = mutableListOf()
15 |
16 | // doTraversal(root, list)
17 | // doTraversalLoop(root, list)
18 | traversal(root, list) // recommended!!!
19 | return list
20 | }
21 |
22 |
23 | private fun traversal(root: TreeNode?, list: MutableList) {
24 | if (root == null) return
25 |
26 | val stk = LinkedList()
27 | stk.addLast(root)
28 |
29 | var node: TreeNode? = null
30 |
31 | while (!stk.isEmpty()) {
32 | node = stk.getLast() // peek
33 |
34 | // the same with if else, but no more null check
35 | node?.let {
36 | // always remove first
37 | stk.removeLast()
38 |
39 | if (it.right != null) stk.addLast(it.right) // right
40 | if (it.left != null) stk.addLast(it.left) // left
41 |
42 | stk.addLast(it) // root
43 | stk.addLast(null)
44 | }?: run {
45 | stk.removeLast()
46 | stk.removeLast()?.apply{
47 | list.add(value)
48 | }
49 | }
50 | }
51 | }
52 |
53 | private fun doTraversalLoop(root: TreeNode?, list: MutableList) {
54 | if (root == null) return
55 | val stk = ArrayDeque()
56 |
57 | var node: TreeNode? = null
58 | stk.addLast(root)
59 |
60 | while (!stk.isEmpty()) {
61 | node = stk.removeLast()
62 | list.add(node.value)
63 |
64 | // here is the key, add right node then left node
65 | node.right?.let {
66 | stk.addLast(it)
67 | }
68 |
69 |
70 | node.left?.let {
71 | stk.addLast(it)
72 | }
73 | }
74 |
75 | return
76 | }
77 |
78 | private fun doTraversal(root: TreeNode?, list: MutableList) {
79 | if (root == null) return
80 |
81 | list.add(root.value)
82 | doTraversal(root.left, list)
83 | doTraversal(root.right, list)
84 | }
85 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/tree/Easy_145_BinaryTreePostorderTraversal.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.tree
2 |
3 | import com.boycoder.basis.datastructure.TreeNode
4 | import java.util.*
5 |
6 | /**
7 | * @Author: zhutao
8 | * @datetime: 2021/6/22
9 | * @desc:
10 | */
11 | object Easy_145_BinaryTreePostorderTraversal {
12 | fun postorderTraversal(root: TreeNode?): List {
13 | val list = mutableListOf()
14 | if (root == null) return list
15 |
16 | // Here we can not use ArrayDeque, it dose allow null element
17 | val stk: Deque = LinkedList()
18 | stk.addLast(root)
19 | var node: TreeNode? = null
20 |
21 | while (!stk.isEmpty()) {
22 | node = stk.getLast()
23 |
24 | if (node != null) {
25 | // always remove first
26 | node = stk.removeLast()
27 |
28 | stk.addLast(node)
29 | stk.addLast(null)
30 |
31 | if (node?.right != null) stk.addLast(node!!.right)
32 | if (node?.left != null) stk.addLast(node!!.left)
33 | } else {
34 | stk.removeLast()
35 | node = stk.removeLast()
36 | list.add(node!!.value)
37 | }
38 | }
39 | return list
40 | }
41 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/tree/Easy_226_InvertBinaryTree.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.tree
2 |
3 | import com.boycoder.basis.datastructure.TreeNode
4 | import java.util.*
5 | import kotlin.collections.ArrayDeque
6 |
7 | /**
8 | * @Author: zhutao
9 | * @datetime: 2021/6/22
10 | * @desc:
11 | */
12 | object Easy_226_InvertBinaryTree {
13 | fun invertTree(root: TreeNode?): TreeNode? {
14 | invert(root)
15 | return root
16 | }
17 |
18 | // loop with level order
19 | private fun invert(root: TreeNode?) {
20 | if (root == null) return
21 |
22 | val queue = ArrayDeque()
23 | queue.addLast(root)
24 |
25 | while (!queue.isEmpty()) {
26 | val node = queue.removeFirst()
27 |
28 | val temp = node.left
29 | node.left = node.right
30 | node.right = temp
31 |
32 | if (node.left != null) queue.addLast(node.left!!)
33 | if (node.right != null) queue.addLast(node.right!!)
34 | }
35 | }
36 |
37 | // loop with post order
38 | private fun invert5(root: TreeNode?) {
39 | if (root == null) return
40 |
41 | val stk = LinkedList()
42 | stk.addLast(root)
43 | var node: TreeNode? = null
44 |
45 | while (!stk.isEmpty()) {
46 | node = stk.getLast()
47 |
48 | node?.let {
49 | stk.removeLast()
50 | stk.addLast(it)
51 | stk.addLast(null)
52 |
53 | if (it.right != null) stk.addLast(it.right)
54 | if (it.left != null) stk.addLast(it.left)
55 | }?: run {
56 | stk.removeLast()
57 | stk.removeLast()?.let {
58 | val temp = it.left
59 | it.left = it.right
60 | it.right = temp
61 | }
62 | }
63 | }
64 | }
65 |
66 | // loop with pre order
67 | private fun invert4(root: TreeNode?) {
68 | if (root == null) return
69 |
70 | val stk = LinkedList()
71 | stk.addLast(root)
72 | var node: TreeNode? = null
73 |
74 | while (!stk.isEmpty()) {
75 | node = stk.getLast()
76 |
77 | node?.let {
78 | stk.removeLast()
79 |
80 | if (it.right != null) stk.addLast(it.right)
81 | if (it.left != null) stk.addLast(it.left)
82 |
83 | stk.addLast(it)
84 | stk.addLast(null)
85 | }?: run {
86 | stk.removeLast()
87 | stk.removeLast()?.let {
88 | val temp = it.left
89 | it.left = it.right
90 | it.right = temp
91 | }
92 | }
93 | }
94 | }
95 |
96 |
97 | // recursion post order
98 | private fun invert3(root: TreeNode?) {
99 | if (root == null) return
100 |
101 | invert(root.left)
102 | invert(root.right)
103 |
104 | val temp = root.left
105 | root.left = root.right
106 | root.right = temp
107 | }
108 |
109 | // recursion inorder
110 | private fun invert2(root: TreeNode?) {
111 | if (root == null) return
112 |
113 | invert(root.left)
114 |
115 | val temp = root.left
116 | root.left = root.right
117 | root.right = temp
118 |
119 |
120 | invert(root.left)
121 | }
122 |
123 | // recursion pre order
124 | private fun invert1(root: TreeNode?) {
125 | if (root == null) return
126 |
127 | val temp = root.left
128 | root.left = root.right
129 | root.right = temp
130 |
131 | invert(root.left)
132 | invert(root.right)
133 | }
134 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/tree/Easy_257_BinaryTreePaths.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.tree
2 |
3 | import com.boycoder.basis.datastructure.TreeNode
4 | import java.util.*
5 |
6 | /**
7 | * @Author: zhutao
8 | * @datetime: 2021/6/22
9 | * @desc:
10 | */
11 | object Easy_257_BinaryTreePaths {
12 | fun binaryTreePaths(root: TreeNode?): List {
13 |
14 | val list = mutableListOf()
15 | if (root == null) return list
16 |
17 | val nodes = mutableListOf()
18 | nodes.add(root)
19 | findPath(root, nodes, list)
20 | return list
21 | }
22 |
23 | /**
24 | * dfs
25 | */
26 | private fun findPath(root: TreeNode, nodes: MutableList, list: MutableList) {
27 |
28 | // time to collect result.
29 | if (root.left == null && root.right == null) {
30 | val s = nodes.joinToString(separator = "->", transform = {
31 | it.value.toString()
32 | })
33 | list.add(s)
34 | return
35 | }
36 |
37 | // find left
38 | if (root.left != null) {
39 | nodes.add(root.left!!)
40 | findPath(root.left!!, nodes, list)
41 | nodes.remove(root.left) // back tracking
42 | }
43 |
44 | // find right
45 | if (root.right != null) {
46 | nodes.add(root.right!!)
47 | findPath(root.right!!, nodes, list)
48 | nodes.remove(root.right) // back tracking
49 | }
50 | }
51 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/tree/Easy_404_SumOfLeftLeaves.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.tree
2 |
3 | import com.boycoder.basis.datastructure.TreeNode
4 | import java.util.*
5 |
6 | /**
7 | * @Author: zhutao
8 | * @datetime: 2021/6/22
9 | * @desc:
10 | */
11 | object Easy_404_SumOfLeftLeaves {
12 | var sum = 0
13 |
14 | fun sumOfLeftLeaves(root: TreeNode?): Int {
15 | sum(root)
16 | return sum
17 | }
18 |
19 | // loop pre order
20 | private fun sum(root: TreeNode?) {
21 | if (root == null) return
22 |
23 | val stk = LinkedList()
24 | stk.addLast(root)
25 | var node: TreeNode? = null
26 |
27 | while (!stk.isEmpty()) {
28 | node = stk.getLast() // peek
29 |
30 | if (node != null) {
31 | stk.removeLast()
32 |
33 | if (node.left != null) stk.addLast(node.left)
34 | if (node.right != null) stk.addLast(node.right)
35 |
36 | stk.addLast(node)
37 | stk.addLast(null)
38 | } else {
39 | stk.removeLast()
40 | stk.removeLast()?.let {
41 | if (it.left != null && it.left!!.left == null && it.left!!.right == null) {
42 | sum = sum + it.left!!.value
43 | }
44 | }
45 | }
46 | }
47 | }
48 |
49 | private fun sum1(root: TreeNode?) {
50 | if (root == null) return
51 |
52 | if (root.left != null && root.left!!.left == null && root.left!!.right == null) {
53 | sum = sum + root.left!!.value
54 | }
55 |
56 | if (root.left != null) sum(root.left)
57 | if (root.right != null) sum(root.right)
58 | }
59 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/tree/Easy_559_MaxDepthNAryTree.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.tree
2 |
3 | /**
4 | * @Author: zhutao
5 | * @datetime: 2021/6/23
6 | * @desc:
7 | */
8 | object Easy_559_MaxDepthNAryTree {
9 | fun maxDepth(root: Node?): Int {
10 | return getDepth(root)
11 | }
12 |
13 | // level traversal
14 | private fun getDepth(root: Node?): Int {
15 | if (root == null) return 0
16 |
17 | val queue = ArrayDeque()
18 | queue.addLast(root)
19 | var depth = 0
20 |
21 | while (!queue.isEmpty()) {
22 | val size = queue.size
23 | depth++
24 |
25 | for (i in 0 until size) {
26 | queue.removeFirst().children.forEach { child ->
27 | if (child != null) {
28 | queue.addLast(child)
29 | }
30 | }
31 | }
32 | }
33 |
34 | return depth
35 | }
36 |
37 |
38 | // recursion
39 | private fun getDepth1(root: Node?): Int {
40 | if (root == null) return 0
41 |
42 | var max = 0
43 | root.children.forEach {
44 | max = Math.max(getDepth(it), max)
45 | }
46 |
47 | return max + 1
48 | }
49 | }
50 |
51 | data class Node(var value: Int, var children: List)
--------------------------------------------------------------------------------
/src/com/boycoder/problems/tree/Easy_617_MergeTwoBinaryTree.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.tree
2 |
3 | import com.boycoder.basis.datastructure.TreeNode
4 | import java.util.*
5 |
6 | /**
7 | * @Author: zhutao
8 | * @datetime: 2021/6/22
9 | * @desc:
10 | */
11 | object Easy_617_MergeTwoBinaryTree {
12 | fun mergeTrees(root1: TreeNode?, root2: TreeNode?): TreeNode? {
13 | return doMerge1(root1, root2)
14 | }
15 |
16 | /**
17 | * loop + stack
18 | */
19 | private fun doMerge1(root1: TreeNode?, root2: TreeNode?): TreeNode? {
20 | if (root1 == null) {
21 | return root2
22 | }
23 |
24 | if (root2 == null) {
25 | return root1
26 | }
27 |
28 | val stk = LinkedList()
29 | stk.addLast(root2)
30 | stk.addLast(root1)
31 |
32 | while (!stk.isEmpty()) {
33 | val node1 = stk.removeLast()
34 | val node2 = stk.removeLast()
35 | node1.value = node1.value + node2.value
36 |
37 | if (node1.left != null && node2.left != null) {
38 | stk.addLast(node2.left)
39 | stk.addLast(node1.left)
40 | }
41 |
42 | if (node1.right != null && node2.right != null) {
43 | stk.addLast(node2.right)
44 | stk.addLast(node1.right)
45 | }
46 |
47 | if (node1.left == null && node2.left != null) {
48 | node1.left = node2.left
49 | }
50 |
51 | if (node1.right == null && node2.right != null) {
52 | node1.right = node2.right
53 | }
54 | }
55 |
56 | return root1
57 | }
58 |
59 | private fun doMerge(root1: TreeNode?, root2: TreeNode?): TreeNode? {
60 | if (root1 == null && root2 == null) {
61 | return null
62 | } else if (root1 == null && root2 != null) {
63 | return root2
64 | } else if (root1 != null && root2 == null) {
65 | return root1
66 | } else if (root1 != null && root2 != null) {
67 | root1.value = root1.value + root2.value
68 | root1.left = doMerge(root1.left, root2.left)
69 | root1.right = doMerge(root1.right, root2.right)
70 | return root1
71 | }
72 |
73 | // can not reach here
74 | return null
75 | }
76 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/tree/Easy_94_BinaryTreeInorderTraversal.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.tree
2 |
3 | import com.boycoder.basis.datastructure.TreeNode
4 | import java.util.*
5 | import kotlin.collections.ArrayDeque
6 |
7 | /**
8 | * @Author: zhutao
9 | * @datetime: 2021/6/22
10 | * @desc:
11 | */
12 | object Easy_94_BinaryTreeInorderTraversal {
13 | fun inorderTraversal(root: TreeNode?): List {
14 | val list = mutableListOf()
15 | if (root == null) return list
16 |
17 | val stk = LinkedList()
18 | stk.addLast(root)
19 | var node: TreeNode? = null
20 |
21 | while (!stk.isEmpty()) {
22 | node = stk.getLast()
23 |
24 | // the same with the if else, but no more null check
25 | node?.let {
26 | // always remove first
27 | stk.removeLast()
28 |
29 | if (it.right != null) stk.addLast(it.right) // right
30 |
31 | stk.addLast(it) // root
32 | stk.addLast(null)
33 |
34 | if (it.left != null) stk.addLast(it.left) // left
35 | }?: run {
36 | stk.removeLast()
37 | stk.removeLast()?.apply {
38 | list.add(value)
39 | }
40 | }
41 | }
42 |
43 | return list
44 | }
45 |
46 |
47 | fun inorderTraversal1(root: TreeNode?): List {
48 | val list = mutableListOf()
49 | val stk = ArrayDeque()
50 |
51 | var node: TreeNode? = root
52 |
53 | while (node != null || !stk.isEmpty()) {
54 | if (node != null) {
55 | stk.addLast(node)
56 | node = node.left
57 | } else {
58 | // really traversal
59 | node = stk.removeLast()
60 | list.add(node.value)
61 |
62 | node = node.right
63 | }
64 | }
65 | return list
66 | }
67 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/tree/Med_102_BinaryTreeLevelOrderTraversal.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.tree
2 |
3 | import com.boycoder.basis.datastructure.TreeNode
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/22
8 | * @desc:
9 | */
10 | object Med_102_BinaryTreeLevelOrderTraversal {
11 | fun levelOrder(root: TreeNode?): List> {
12 | val list: MutableList> = mutableListOf()
13 | if (root == null) return list
14 |
15 | val queue = ArrayDeque()
16 |
17 | var node = root
18 | queue.addLast(root)
19 |
20 | while (!queue.isEmpty()) {
21 | val size = queue.size
22 | val temps = mutableListOf()
23 |
24 |
25 | for (i in 0 until size) {
26 | node = queue.removeFirst()
27 | temps.add(node.value)
28 |
29 | if (node.left != null) queue.addLast(node.left!!)
30 | if (node.right != null) queue.addLast(node.right!!)
31 | }
32 |
33 | list.add(temps)
34 | }
35 | return list
36 | }
37 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/tree/Med_106_ConstructBinaryTree.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.tree
2 |
3 | import com.boycoder.basis.datastructure.TreeNode
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/22
8 | * @desc:
9 | */
10 | object Med_106_ConstructBinaryTree {
11 |
12 |
13 | /**
14 | * inorder: 9,3,15,20,7
15 | * postorder:9,15,7,20,3
16 | *
17 | * 9 3 15,20,7
18 | * 9 15,7,20 3
19 | * | | \
20 | * 9 3 15, 20 7
21 | * 9 3 15,7, 20
22 | * / | \
23 | * 15 20 7
24 | *
25 | *
26 | */
27 | fun buildTree(inorder: IntArray, postorder: IntArray): TreeNode? {
28 | if (inorder.size == 0 || postorder.size == 0) return null
29 |
30 | val pRoot = postorder.size - 1
31 | val iRoot = inorder.indexOf(postorder[pRoot])
32 |
33 | var node = TreeNode(postorder[pRoot])
34 |
35 | if (postorder.size == 1) {
36 | return node
37 | }
38 |
39 | if (iRoot == 0) {
40 | node.right = buildTree(inorder.slice(1..(inorder.size - 1)).toIntArray(), postorder.slice(0..(postorder.size - 2)).toIntArray())
41 | } else if (iRoot == inorder.size - 1) {
42 | node.left = buildTree(inorder.slice(0..(inorder.size - 2)).toIntArray(), postorder.slice(0..(postorder.size - 2)).toIntArray())
43 | } else {
44 | // in the middle
45 | val leftSize = iRoot
46 | val rightSize = inorder.size - 1 - iRoot
47 | node.left = buildTree(inorder.slice(0..(leftSize - 1)).toIntArray(), postorder.slice(0..(leftSize - 1)).toIntArray())
48 | node.right = buildTree(inorder.slice((iRoot + 1)..(inorder.size - 1)).toIntArray(), postorder.slice(leftSize..(postorder.size - 2)).toIntArray())
49 | }
50 |
51 | return node
52 | }
53 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/tree/Med_222_CompleteTreeNodeCount.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.tree
2 |
3 | import com.boycoder.basis.datastructure.TreeNode
4 | import java.util.*
5 |
6 | /**
7 | * @Author: zhutao
8 | * @datetime: 2021/6/22
9 | * @desc:
10 | */
11 | object Med_222_CompleteTreeNodeCount {
12 | fun countNodes(root: TreeNode?): Int {
13 | return count1(root)
14 | }
15 |
16 | private fun count1(root: TreeNode?): Int {
17 | if (root == null) return 0
18 |
19 | var count = 0
20 | val queue = LinkedList()
21 | queue.addLast(root)
22 |
23 | while (!queue.isEmpty()) {
24 | val node = queue.removeFirst()
25 | count++
26 |
27 | node.left?.let {
28 | queue.addLast(it)
29 | }
30 |
31 | node.right?.let {
32 | queue.addLast(it)
33 | }
34 | }
35 |
36 | return count
37 | }
38 |
39 | /**
40 | * post order
41 | */
42 | private fun count(root: TreeNode?): Int {
43 | if (root == null) return 0
44 |
45 | val left = count(root.left)
46 | val right = count(root.right)
47 |
48 | return left + right + 1
49 | }
50 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/tree/Med_236_LowestCommonAncestor.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.tree
2 |
3 | import com.boycoder.basis.datastructure.TreeNode
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/22
8 | * @desc:
9 | *
10 | * 1. Recursion + post order
11 | * 2. Maintain every node's parent in map
12 | * and find visit every p node parent put into the set.
13 | * Then visit every q node parent check if into the set.
14 | */
15 | object Med_236_LowestCommonAncestor {
16 |
17 | fun lowestCommonAncestor(root: TreeNode?, p: TreeNode?, q: TreeNode?): TreeNode? {
18 | if (root == null || p == null || q == null) return null
19 | return find(root, p, q)
20 | }
21 |
22 | // recursion + post order
23 | private fun find(root: TreeNode?, p: TreeNode, q: TreeNode): TreeNode? {
24 | if (root == null) return null
25 |
26 | val left = find(root.left, p, q)
27 | val right = find(root.right, p, q)
28 |
29 | if (root.value == p.value || root.value == q.value) return root
30 |
31 | if (left != null && right != null) {
32 | return root
33 | } else if (left == null && right != null) {
34 | return right
35 | } else if (left != null && right == null) {
36 | return left
37 | } else {
38 | return null
39 | }
40 | }
41 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/tree/Med_513_BottomLeftTreeValue.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.tree
2 |
3 | import com.boycoder.basis.datastructure.TreeNode
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/22
8 | * @desc:
9 | */
10 | object Med_513_BottomLeftTreeValue {
11 | var maxLevel = 0
12 | var value = 0
13 | fun findBottomLeftValue(root: TreeNode?): Int {
14 | findLeft(root)
15 | return value
16 | }
17 |
18 | private fun findLeft(root: TreeNode?) {
19 | if (root == null) return
20 |
21 | val queue = ArrayDeque()
22 | queue.addLast(root)
23 | var node = root
24 |
25 | while (!queue.isEmpty()) {
26 | val size = queue.size
27 |
28 | for (i in 0 until size) {
29 | node = queue.removeFirst()
30 | if (i == 0) {
31 | maxLevel++
32 | value = node.value
33 | }
34 |
35 | node.left?.let {
36 | queue.addLast(it)
37 | }
38 |
39 | node.right?.let {
40 | queue.addLast(it)
41 | }
42 | }
43 | }
44 | }
45 |
46 | // recursion with back tracking
47 | private fun findLeft1(root: TreeNode?, level: Int) {
48 | if (root == null) return
49 |
50 | var mLevel = level
51 | if (mLevel > maxLevel) {
52 | maxLevel = mLevel
53 | value = root.value
54 | }
55 |
56 | // we check left node first, so we can find bottom left
57 | // if change the order, we can find bottom right
58 | if (root.left != null) {
59 | mLevel++
60 | findLeft1(root.left, mLevel)
61 | mLevel--
62 | }
63 |
64 | if (root.right != null) {
65 | mLevel++
66 | findLeft1(root.right, mLevel)
67 | mLevel--
68 | }
69 | }
70 | }
--------------------------------------------------------------------------------
/src/com/boycoder/problems/tree/Med_654_MaxBinaryTree.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.problems.tree
2 |
3 | import com.boycoder.basis.datastructure.TreeNode
4 |
5 | /**
6 | * @Author: zhutao
7 | * @datetime: 2021/6/22
8 | * @desc:
9 | */
10 | object Med_654_MaxBinaryTree {
11 |
12 | fun constructMaximumBinaryTree(nums: IntArray): TreeNode? {
13 | val size = nums.size
14 | if (size == 0) return null
15 | var max = -1
16 | var index = 0
17 | nums.forEachIndexed { indx, i ->
18 | if (i > max) {
19 | max = i
20 | index = indx
21 | }
22 | }
23 |
24 | val node = TreeNode(max)
25 | if (size == 1) return node
26 |
27 | if (index == 0) {
28 | node.right = constructMaximumBinaryTree(nums.slice(1..(size - 1)).toIntArray())
29 | } else if (index == size - 1) {
30 | node.left = constructMaximumBinaryTree(nums.slice(0..(size - 2)).toIntArray())
31 | } else {
32 | node.left = constructMaximumBinaryTree(nums.slice(0..(index - 1)).toIntArray())
33 | node.right = constructMaximumBinaryTree(nums.slice((index + 1)..(size - 1)).toIntArray())
34 | }
35 |
36 | return node
37 | }
38 | }
--------------------------------------------------------------------------------
/src/com/boycoder/utils/Utils.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.utils
2 |
3 | fun asserts(res: Any?, expect: Any?) {
4 | if (res != expect) {
5 | throw WrongResultException("\n" +
6 | "=================\n" +
7 | "res: $res \nexpect: $expect")
8 | } else {
9 | println("success")
10 | }
11 | }
12 |
13 | fun assertCollection(res: Collection, expect: Collection) {
14 | if (res.size != res.size) {
15 | throw WrongResultException("\n" +
16 | "=================\n" +
17 | "res: $res \nexpect: $expect")
18 | }
19 |
20 | val iterator1 = res.iterator()
21 | val iterator2 = expect.iterator()
22 | while (iterator1.hasNext() && iterator2.hasNext()) {
23 | val v1 = iterator1.next()
24 | val v2 = iterator2.next()
25 |
26 | if (v1 != v2) {
27 | throw WrongResultException("\n" +
28 | "=================\n" +
29 | "res: $res \nexpect: $expect")
30 | }
31 | }
32 |
33 | println("success")
34 | }
35 |
36 | /**
37 | * increase
38 | */
39 | fun isSorted(array: IntArray): Boolean {
40 | for (i in 1 until array.size) {
41 | if (array[i - 1] > array[i]) {
42 | return false
43 | }
44 | }
45 |
46 | return true
47 | }
--------------------------------------------------------------------------------
/src/com/boycoder/utils/WrongResultException.kt:
--------------------------------------------------------------------------------
1 | package com.boycoder.utils
2 |
3 | class WrongResultException(msg: String): Exception(msg) {
4 | }
--------------------------------------------------------------------------------