Skip to content

Commit 7bb4371

Browse files
committed
Algocasts P063.
1 parent 6fb5f44 commit 7bb4371

File tree

11 files changed

+263
-22
lines changed

11 files changed

+263
-22
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
- [algocasts](algocasts)[AlgoCasts](https://algocasts.io/)
44
- [algs4](algs4)[算法(第4版)](http://www.ituring.com.cn/book/875)
5-
- [algs4-scala](algs4-scala):算法(第4版)Scala实现,初始源码来自https://github.com/garyaiki/Scala-Algorithms.git
5+
- [algs4-scala](algs4-scala):算法(第4版)Scala实现
66
- [leetcode](leetcode):leetcode 习题
77
- [algorithm](algorithm):[算法图解](https://www.ituring.com.cn/book/1864)
88
- [算法的乐趣](http://www.ituring.com.cn/book/1605)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package series
2+
3+
import scala.collection.mutable
4+
5+
/**
6+
* P61. 天际线
7+
* https://algocasts.io/series/algo-problems-51-100/episodes/LPmwqNpq
8+
* (left, right, high)
9+
*
10+
* 这个题目说的是,给你一组矩形表示的楼房,它们的底边在同一水平线上,并且楼房之间可以相邻,也可以重叠。你要找到这组楼房的轮廓线或者叫天际线,
11+
* 并返回这个轮廓线的关键点。
12+
*/
13+
object P061Skyline {
14+
final case class Rect(left: Int, right: Int, high: Int)
15+
16+
// Time: O(n^2), Space: O(n)
17+
def skylinePointsMaxHeap(bindings: Vector[Rect]): Vector[(Int, Int)] = {
18+
var result: Vector[(Int, Int)] = Vector()
19+
val height: Vector[(Int, Int)] = bindings
20+
.flatMap { arr =>
21+
(arr.left, -arr.high) :: (arr.right, arr.high) :: Nil
22+
}
23+
.sortWith { case ((aX, aH), (bX, bH)) => if (aX == bX) aH < bH else aX < bX }
24+
25+
var pq = mutable.PriorityQueue[Int](0) // Maximum in queue header.
26+
var preHeight = 0
27+
for ((x, h) <- height) {
28+
if (h < 0) pq.enqueue(-h)
29+
else pq = pq.filterNot(_ == h)
30+
31+
if (pq.head != preHeight) {
32+
preHeight = pq.head
33+
result :+= x -> pq.head
34+
}
35+
}
36+
37+
result
38+
}
39+
40+
// Time: O(nlog(n)), Space: O(n)
41+
def skylinePointsTreeMap(bindings: Vector[Rect]): Vector[(Int, Int)] = {
42+
var result: Vector[(Int, Int)] = Vector()
43+
val height: Vector[(Int, Int)] = bindings
44+
.flatMap { arr =>
45+
(arr.left, -arr.high) :: (arr.right, arr.high) :: Nil
46+
}
47+
.sortWith { case ((aX, aH), (bX, bH)) => if (aX == bX) aH < bH else aX < bX }
48+
49+
val tree = mutable.TreeMap[Int, Int](0 -> 1)
50+
var preHeight = 0
51+
for ((x, h) <- height) {
52+
if (h < 0) {
53+
tree.updateWith(-h) {
54+
case Some(n) => Some(n + 1)
55+
case None => Some(1)
56+
}
57+
} else {
58+
tree.updateWith(h) {
59+
case Some(1) => None
60+
case Some(n) => Some(n - 1)
61+
case None => None
62+
}
63+
}
64+
65+
val max = tree.lastKey
66+
if (max != preHeight) {
67+
preHeight = max
68+
result :+= x -> max
69+
}
70+
}
71+
72+
result
73+
}
74+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package series
2+
3+
import scala.collection.mutable
4+
5+
/**
6+
* P62. 路径和是否等于给定值
7+
* https://algocasts.io/series/algo-problems-51-100/episodes/17WMBomj
8+
* 这个题目说的是,给你一棵二叉树和一个整数,你要判断这棵二叉树上是否存在一条从根到叶子节点的路径,这条路径上所有节点中的数字相加等于给你的整数。
9+
*
10+
* 比如说,给你的二叉树是:
11+
* <pre>
12+
* 1
13+
* / \
14+
* 2 4
15+
* / \
16+
* 8 16
17+
* </pre>
18+
* 给你的整数是 13。在这棵二叉树中存在一条从根到叶子节点的路径 1->4->8,路径上的数字加起来等于 13,于是要返回 true。
19+
*/
20+
object P062BTHasPathSum {
21+
final class TreeNode(val value: Int, var left: TreeNode = null, var right: TreeNode = null)
22+
23+
// Time: O(n), Space: O(n)
24+
def hasPathSumRecursive(root: TreeNode, sum: Int): Boolean = {
25+
if (null == root) false
26+
else if (root.left == null && root.right == null) root.value == sum
27+
else hasPathSumRecursive(root.left, sum - root.value) || hasPathSumRecursive(root.right, sum - root.value)
28+
}
29+
30+
// Time: O(n), Space: O(n)
31+
def hasPathSumIterative(root: TreeNode, sum: Int): Boolean = {
32+
if (null == root) return false
33+
34+
val stack = mutable.Stack[TreeNode](root)
35+
val sumStack = mutable.Stack[Int](sum)
36+
37+
while (stack.nonEmpty) {
38+
val node = stack.pop()
39+
val n = sumStack.pop()
40+
41+
if (node.left == null && node.right == null && node.value == n) return true
42+
43+
if (node.left != null) {
44+
stack.push(node.left)
45+
sumStack.push(n - node.value)
46+
}
47+
if (node.right != null) {
48+
stack.push(node.right)
49+
sumStack.push(n - node.value)
50+
}
51+
}
52+
53+
false
54+
}
55+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package series
2+
3+
/**
4+
* P63. 用前序和中序遍历序列构建二叉树
5+
* https://algocasts.io/series/algo-problems-51-100/episodes/M0G2DaWz
6+
* 这个题目说的是,给你一棵二叉树的前序和中序遍历序列,你要根据这两个序列构建这棵二叉树。假设这棵二叉树节点上没有重复的数字。
7+
*
8+
* 比如说,给你的前序遍历序列和中序遍历序列分别是:
9+
* <pre>
10+
* 前序遍历序列:1, 2, 4, 8, 16
11+
* 中序遍历序列:2, 1, 8, 4, 16
12+
*
13+
* 你要返回用它们构建出的二叉树,是:
14+
*
15+
* 1
16+
* / \
17+
* 2 4
18+
* / \
19+
* 8 16
20+
* </pre>
21+
*/
22+
object P063PreInBuildTree {
23+
case class TreeNode(value: Int, var left: TreeNode = null, var right: TreeNode = null)
24+
25+
// Time: O(n), Space: O(n)
26+
def buildTree(pre: IndexedSeq[Int], in: IndexedSeq[Int]): TreeNode = {
27+
val inPos = in.zipWithIndex.map { case (n, i) => n -> i }.toMap
28+
29+
def _buildTree(preStart: Int, preEnd: Int, inStart: Int): TreeNode = {
30+
if (preStart > preEnd) return null
31+
32+
val root = TreeNode(pre(preStart))
33+
val rootIdx = inPos(root.value)
34+
val leftLen = rootIdx - inStart
35+
root.left = _buildTree(preStart + 1, preStart + leftLen, inStart)
36+
root.right = _buildTree(preStart + leftLen + 1, preEnd, rootIdx + 1)
37+
root
38+
}
39+
40+
_buildTree(0, pre.length - 1, 0)
41+
}
42+
}

algocasts/src/test/scala/series/P059KthLargestTest.scala

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
package series
22

3-
import org.scalatest.{ FunSuite, Matchers }
3+
import org.scalatest.funsuite.AnyFunSuite
4+
import org.scalatest.matchers.should.Matchers
45

5-
class P059KthLargestTest extends FunSuite with Matchers {
6+
class P059KthLargestTest extends AnyFunSuite with Matchers {
67
import P059KthLargest._
78
test("testFindKthLargestQuickSelect") {
89
findKthLargestQuickSelect(Array(1, 2, 3, 4, 5), 2) should be(4)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package series
2+
3+
import org.scalatest.matchers.should.Matchers
4+
import org.scalatest.wordspec.AnyWordSpec
5+
6+
class P061SkylineTest extends AnyWordSpec with Matchers {
7+
import P061Skyline._
8+
9+
private val data1 = Vector(Rect(1, 3, 2), Rect(2, 4, 3), Rect(5, 9, 2), Rect(6, 8, 4))
10+
private val result1 = Vector((1, 2), (2, 3), (4, 0), (5, 2), (6, 4), (8, 2), (9, 0))
11+
private val data2 = Vector(Rect(2, 4, 2), Rect(2, 4, 3), Rect(5, 7, 2), Rect(7, 9, 4))
12+
private val result2 = Vector((2, 3), (4, 0), (5, 2), (7, 4), (9, 0))
13+
14+
"MaxHeap" should {
15+
"X axis does not coincide" in {
16+
skylinePointsMaxHeap(data1) shouldBe result1
17+
}
18+
19+
"X axis coincidence" in {
20+
skylinePointsMaxHeap(data2) shouldBe result2
21+
}
22+
}
23+
24+
"TreeMap" should {
25+
"X axis does not coincide" in {
26+
skylinePointsTreeMap(data1) shouldBe result1
27+
}
28+
29+
"X axis coincidence" in {
30+
skylinePointsTreeMap(data2) shouldBe result2
31+
}
32+
}
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package series
2+
3+
import org.scalatest.matchers.should.Matchers
4+
import org.scalatest.wordspec.AnyWordSpec
5+
6+
class P062BTHasPathSumTest extends AnyWordSpec with Matchers {
7+
import P062BTHasPathSum._
8+
private val tree = new TreeNode(1, new TreeNode(2), new TreeNode(4, new TreeNode(8), new TreeNode(16)))
9+
10+
"Recursive" should {
11+
"Has true" in { hasPathSumRecursive(tree, 13) shouldBe true }
12+
13+
"Has false" in { hasPathSumRecursive(tree, 14) shouldBe false }
14+
}
15+
"Iterative" should {
16+
"Has true" in { hasPathSumIterative(tree, 13) shouldBe true }
17+
18+
"Has false" in { hasPathSumIterative(tree, 14) shouldBe false }
19+
}
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package series
2+
3+
import org.scalatest.matchers.should.Matchers
4+
import org.scalatest.wordspec.AnyWordSpec
5+
6+
class P063PreInBuildTreeTest extends AnyWordSpec with Matchers {
7+
import P063PreInBuildTree._
8+
9+
"PreIn" should {
10+
"tree" in {
11+
buildTree(Vector(1, 2, 4, 8, 16), Vector(2, 1, 8, 4, 16)) should be(
12+
TreeNode(1, TreeNode(2), TreeNode(4, TreeNode(8), TreeNode(16))))
13+
}
14+
}
15+
}

algs4-scala/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
初始源码来自 [https://github.com/garyaiki/Scala-Algorithms.git][https://github.com/garyaiki/Scala-Algorithms.git]

algs4-scala/src/main/scala/org/gs/symboltable/RedBlackBST.scala

+17-17
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ sealed class Node[A, B](var key: A, var value: B, var count: Int = 1, var red: B
2727
class RedBlackBST[A, B](implicit ord: Ordering[A]) {
2828
private var root = null.asInstanceOf[Node[A, B]]
2929

30-
private def isRed(x: Node[A, B]): Boolean = if ((x == null) || (x.red == false)) false else true
30+
private def isRed(x: Node[A, B]): Boolean = x != null && x.red
3131

32-
/** Make h.right the new root of subtree
32+
/** Make h.right the new root of subtree and return it
3333
*
3434
* if h.right is red rotate left so h becomes the left child and h.right becomes the parent
3535
*/
@@ -45,7 +45,7 @@ class RedBlackBST[A, B](implicit ord: Ordering[A]) {
4545
x
4646
}
4747

48-
/** Make h.left the new root of subtree
48+
/** Make h.left the new root of subtree and return it
4949
*
5050
* if h.left is red rotate right so h becomes the right child and h.left becomes the parent
5151
*/
@@ -54,7 +54,7 @@ class RedBlackBST[A, B](implicit ord: Ordering[A]) {
5454
val x = h.left
5555
h.left = x.right
5656
x.right = h
57-
x.red = x.right.red
57+
x.red = x.right.red // equals h.red
5858
x.right.red = true
5959
x.count = h.count
6060
h.count = 1 + size(h.left) + size(h.right)
@@ -82,9 +82,9 @@ class RedBlackBST[A, B](implicit ord: Ordering[A]) {
8282
if (x == null) new Node(key, value)
8383
else {
8484
ord.compare(key, x.key) match {
85-
case 0 => x.value = value
86-
case n if (n < 0) => x.left = loop(x.left)
87-
case _ => x.right = loop(x.right)
85+
case 0 => x.value = value
86+
case n if n < 0 => x.left = loop(x.left)
87+
case _ => x.right = loop(x.right)
8888
}
8989
x.count += 1
9090
if (isRed(x.right) && !isRed(x.left)) rotateLeft(x)
@@ -109,9 +109,9 @@ class RedBlackBST[A, B](implicit ord: Ordering[A]) {
109109
if (x == null) None
110110
else {
111111
ord.compare(key, x.key) match {
112-
case 0 => Some(x.value)
113-
case n if (n < 0) => loop(x.left)
114-
case _ => loop(x.right)
112+
case 0 => Some(x.value)
113+
case n if n < 0 => loop(x.left)
114+
case _ => loop(x.right)
115115
}
116116
}
117117
loop(root)
@@ -125,13 +125,13 @@ class RedBlackBST[A, B](implicit ord: Ordering[A]) {
125125

126126
def loop(x: Node[A, B], key: A): Node[A, B] = {
127127
val h = ord.compare(key, x.key) match {
128-
case n if (n < 0) => {
128+
case n if n < 0 => // go left
129129
val j = if (!isRed(x.left) && !isRed(x.left.left)) moveRedLeft(x) else x
130130

131131
j.left = loop(j.left, key)
132132
j
133-
}
134-
case _ => {
133+
134+
case _ =>
135135
val j = if (isRed(x.left)) rotateRight(x) else x
136136

137137
ord.compare(key, j.key) match {
@@ -150,7 +150,6 @@ class RedBlackBST[A, B](implicit ord: Ordering[A]) {
150150
k
151151
}
152152
}
153-
}
154153
}
155154
balance(h)
156155
}
@@ -189,7 +188,7 @@ class RedBlackBST[A, B](implicit ord: Ordering[A]) {
189188
}
190189

191190
private def deleteMin(h: Node[A, B]): Node[A, B] = {
192-
if (h.left == null) null
191+
if (h.left == null) null // delete current node
193192
else {
194193
val j = if (!isRed(h.left) && !isRed(h.left.left)) moveRedLeft(h) else h
195194
j.left = deleteMin(j.left)
@@ -199,6 +198,7 @@ class RedBlackBST[A, B](implicit ord: Ordering[A]) {
199198

200199
/** delete minimum key */
201200
def deleteMin(): Unit = {
201+
// 确保节点为 RED
202202
if (!isRed(root.left) && !isRed(root.right)) root.red = true
203203

204204
root = deleteMin(root)
@@ -236,11 +236,11 @@ class RedBlackBST[A, B](implicit ord: Ordering[A]) {
236236
/** is key present */
237237
def contains(key: A): Boolean = get(key) match {
238238
case None => false
239-
case Some(x) => if (x == null) false else true
239+
case Some(x) => x != null
240240
}
241241

242242
/** are any keys in tree */
243-
def isEmpty(): Boolean = if (root == null) true else false
243+
def isEmpty(): Boolean = root == null
244244

245245
@tailrec
246246
private def min(x: Node[A, B]): Node[A, B] = {

algs4/src/main/java/edu/princeton/cs/algs4/BST.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -208,8 +208,8 @@ private Node delete(Node x, Key key) {
208208
if (x.left == null) return x.right;
209209
Node t = x;
210210
x = min(t.right);
211-
x.right = deleteMin(t.right);
212-
x.left = t.left;
211+
x.right = deleteMin(t.right); // 待删除节点的已删除最小值的右子树
212+
x.left = t.left; // 待删除节点的左子树
213213
}
214214
x.size = size(x.left) + size(x.right) + 1;
215215
return x;

0 commit comments

Comments
 (0)