@@ -1458,7 +1458,346 @@ def test_25():
1458
1458
assert not regexMatched ("*a." , "blablablaay" )
1459
1459
1460
1460
1461
- test_25 ()
1461
+ """
1462
+ question 26
1463
+
1464
+ Given a singly linked list and an integer k, remove the kth last element from
1465
+ the list. k is guaranteed to be smaller than the length of the list.
1466
+
1467
+ The list is very long, so making more than one pass is prohibitively expensive.
1468
+
1469
+ Do this in constant space and in one pass.
1470
+ --------------------
1471
+
1472
+ It's a single linked list, we can only travel from left to right follwing
1473
+ the next pointer in each node.
1474
+
1475
+ Use two pointers to travel the linked list from left to right in one pass.
1476
+ Initially p1 points to the head of the list, p2 points to the kth element of
1477
+ the list. Then p1 and p2 go left along the list with the same pace,
1478
+ one step at a time, until p2 reach the end of the list. p1 is pointing to the
1479
+ kth last element of the list.
1480
+ k = 3
1481
+ a -> b -> c -> d -> e -> f -> g
1482
+ ^ ^
1483
+ ^ ^
1484
+ return 'e'
1485
+ """
1486
+
1487
+
1488
+ def test_26 ():
1489
+ pass
1490
+
1491
+
1492
+ """
1493
+ question 27
1494
+ Given a string of round, curly, and square open and closing brackets, return
1495
+ whether the brackets are balanced (well-formed).
1496
+
1497
+ For example, given the string "([])[]({})", you should return true.
1498
+
1499
+ Given the string "([)]" or "((()", you should return false.
1500
+ ---------------------
1501
+
1502
+ Instintively, a stack can help use here but why?
1503
+ To do this, iterate through the string:
1504
+ For every opening, it needs to pair to a later unmatched closing. But considering
1505
+ nesting scenarios, an opening can follow up another opening. So we need to reserve
1506
+ unmatched openings somewhere. when a closing is comming, it needs to pair with
1507
+ the most recent unmatched opening.
1508
+ So a stack, as its Last-In-First-Out nature, is a good fit for this
1509
+ Iterate through the string, process every bracket:
1510
+ - if it's opening, push to the stack.
1511
+ - if it's closing, pop from the stack (the stack should be non-empty) and pair them.
1512
+ - If not pair, return early.
1513
+ - Until we complete all brackets in the string. If the stack is empty, it's balanced.
1514
+ Otherwise, unbalanced
1515
+ """
1516
+
1517
+
1518
+ def test_27 ():
1519
+ pass
1520
+
1521
+
1522
+ """
1523
+ question 28
1524
+ Write an algorithm to justify text. Given a sequence of words and an integer
1525
+ line length k, return a list of strings which represents each line, fully
1526
+ justified.
1527
+
1528
+ More specifically, you should have as many words as possible in each line. There
1529
+ should be at least one space between each word. Pad extra spaces when necessary
1530
+ so that each line has exactly length k. Spaces should be distributed as equally
1531
+ as possible, with the extra spaces, if any, distributed starting from the left.
1532
+
1533
+ If you can only fit one word on a line, then you should pad the right-hand side
1534
+ with spaces.
1535
+
1536
+ Each word is guaranteed not to be longer than k.
1537
+
1538
+ For example, given the list of words ["the", "quick", "brown", "fox", "jumps",
1539
+ "over", "the", "lazy", "dog"] and k = 16, you should return the following:
1540
+
1541
+ ["the quick brown", # 1 extra space on the left
1542
+ "fox jumps over", # 2 extra spaces distributed evenly
1543
+ "the lazy dog"] # 4 extra spaces distributed evenly"
1544
+
1545
+ -------------------
1546
+ iterate words, trying to fit in as much words as possible.
1547
+ use two pointers, first pointer is the first word of current line and
1548
+ second pointer is the word to check whether it can be fit in to current line.
1549
+
1550
+ ["the", "quick", "brown", "fox", "jumps", "over", "the", "lazy", "dog"]
1551
+ i1
1552
+ i2
1553
+ initially i1 = 0
1554
+ cur_len = len(word[i1])
1555
+ when add new word[i2], new length is cur_len + len(word[i2]) + 1
1556
+ if cur_len is smaller or equal to k:
1557
+ move i2 forward.
1558
+ otherwise:
1559
+ create a new line with words from i1 to i2-1;
1560
+ distribute the extra spaces evenly between words starting from left
1561
+ remaining_spaces = k - cur_len
1562
+ number of spaces in words: total_num = i2 - i1
1563
+ even space number: even_spaces = 1 + remaining_spaces // total_num
1564
+ extra_remaining: remaining_spaces % total_num
1565
+ move i1 to i2 as the first word and move i2 forward
1566
+ """
1567
+
1568
+
1569
+ def justify_text (words , k ):
1570
+ # generate line with words [start, end)
1571
+ # cur_len is the length with words and one space between words
1572
+ def generate_one_line (start : int , end : int , cur_len : int ):
1573
+ new_line = ""
1574
+ space_num = end - start - 1
1575
+ if space_num == 1 :
1576
+ # only one word in the line
1577
+ new_line += words [start ]
1578
+ new_line += " " * (k - len (words [start ]))
1579
+ return new_line
1580
+ small_space_num = 1 + (k - cur_len ) // (space_num )
1581
+ small_spaces = " " * small_space_num
1582
+ large_spaces = small_spaces + " "
1583
+ # print(f"'{large_spaces}'")
1584
+ large_space_num = (k - cur_len ) % (space_num )
1585
+ new_line += words [i1 ]
1586
+ for i in range (1 , space_num + 1 ):
1587
+ if i <= large_space_num :
1588
+ new_line += large_spaces
1589
+ else :
1590
+ new_line += small_spaces
1591
+ new_line += words [start + i ]
1592
+ return new_line
1593
+
1594
+ lines = []
1595
+ i1 = 0
1596
+ cur_len = len (words [0 ])
1597
+ for i2 in range (1 , len (words )):
1598
+ if cur_len + len (words [i2 ]) + 1 > k :
1599
+ # needs to generate new line with words in [i1, i2)
1600
+ lines .append (generate_one_line (i1 , i2 , cur_len ))
1601
+ i1 = i2
1602
+ cur_len = len (words [i1 ])
1603
+ else :
1604
+ cur_len = cur_len + len (words [i2 ]) + 1
1605
+ # process left_over words from i1 to the end
1606
+ lines .append (generate_one_line (i1 , len (words ), cur_len ))
1607
+ return lines
1608
+
1609
+
1610
+ def test_28 ():
1611
+ words = ["the" , "quick" , "brown" , "fox" , "jumps" , "over" , "the" , "lazy" , "dog" ]
1612
+ k = 16
1613
+ assert justify_text (words , k ) == [
1614
+ "the quick brown" ,
1615
+ "fox jumps over" ,
1616
+ "the lazy dog" ,
1617
+ ]
1618
+
1619
+
1620
+ """
1621
+ question 29
1622
+ Run-length encoding is a fast and simple method of encoding strings. The basic
1623
+ idea is to represent repeated successive characters as a single count and
1624
+ character. For example, the string "AAAABBBCCDAA" would be encoded as
1625
+ "4A3B2C1D2A".
1626
+
1627
+ Implement run-length encoding and decoding. You can assume the string to be
1628
+ encoded have no digits and consists solely of alphabetic characters. You can
1629
+ assume the string to be decoded is valid.
1630
+
1631
+ -------------------
1632
+ "AAAABBBCCDAA"
1633
+ ^
1634
+ ^
1635
+ 42A3B2C
1636
+ ^
1637
+
1638
+ num = num * 10 + int(c)
1639
+ """
1640
+
1641
+
1642
+ def run_length_encoding (text ):
1643
+ i1 = 0
1644
+ encoded = ""
1645
+ c1 = text [0 ]
1646
+ for i2 in range (len (text )):
1647
+ c2 = text [i2 ]
1648
+ if c1 != c2 :
1649
+ encoded += str (i2 - i1 )
1650
+ encoded += c1
1651
+ i1 = i2
1652
+ c1 = c2
1653
+ # process left_over
1654
+ encoded += str (len (text ) - i1 )
1655
+ encoded += text [i1 ]
1656
+ return encoded
1657
+
1658
+
1659
+ def run_length_decoding (encoded ):
1660
+ num = 0
1661
+ text = ""
1662
+ for i2 in range (len (encoded )):
1663
+ c = encoded [i2 ]
1664
+ if "0" <= c <= "9" :
1665
+ num = num * 10 + int (c )
1666
+ else :
1667
+ # decode sequence of one character
1668
+ text += c * num
1669
+ num = 0
1670
+ return text
1671
+
1672
+
1673
+ def test_29 ():
1674
+ text = "AAAABBBCCDAA"
1675
+ assert run_length_decoding (run_length_encoding (text )) == text
1676
+ text = "AAAAAAAAAAAAAAAABBBCCDDDDDDDDDDDAA"
1677
+ assert run_length_decoding (run_length_encoding (text )) == text
1678
+
1679
+
1680
+ """
1681
+ question 30
1682
+ You are given an array of non-negative integers that represents a
1683
+ two-dimensional elevation map where each element is unit-width wall and the
1684
+ integer is the height. Suppose it will rain and all spots between two walls get
1685
+ filled up.
1686
+
1687
+ Compute how many units of water remain trapped on the map in O(N) time and O(1)
1688
+ space.
1689
+
1690
+ For example, given the input [2, 1, 2], we can hold 1 unit of water in the
1691
+ middle.
1692
+
1693
+ Given the input [3, 0, 1, 3, 0, 5], we can hold 3 units in the first index, 2 in
1694
+ the second, and 3 in the fourth index (we cannot hold 5 since it would run off
1695
+ to the left), so we can trap 8 units of water.
1696
+
1697
+ -------------------
1698
+ [2,1,2]
1699
+ | |
1700
+ | | |
1701
+ for ith element,
1702
+ - left_max_wall is the max height in heights[0, i],
1703
+ - right_max_wall is the max height in heights[i, N-1]
1704
+ so the water height is min(left_max_wall, right_max_wall) - cur_wall_height
1705
+
1706
+ [2,1,2]
1707
+ left_max_array: [2,2,2]
1708
+ right_max_array:[2,2,2]
1709
+
1710
+
1711
+ left_max_array = [0] * N
1712
+ left_max_array[0] = heights[0]
1713
+ for i in range(1, len(heights)):
1714
+ left_max_array[i] = max(left_max_array[i-1], heights[i])
1715
+ right_max_array = [0] * N
1716
+ right_max_array[N-1] = heights[N-1]
1717
+ for i in range(N-2, -1, -1):
1718
+ right_max_array = max(right_max_array(i+1), heights[i])
1719
+ time O(N), space O(N)
1720
+ TODO how to optimize to time O(N), space O(1)
1721
+ """
1722
+
1723
+
1724
+ def totalTrappedWater (heights ):
1725
+ N = len (heights )
1726
+ left_max_array = [0 ] * N
1727
+ left_max_array [0 ] = heights [0 ]
1728
+ for i in range (1 , N ):
1729
+ left_max_array [i ] = max (left_max_array [i - 1 ], heights [i ])
1730
+ right_max_array = [0 ] * N
1731
+ right_max_array [N - 1 ] = heights [N - 1 ]
1732
+ for i in range (N - 2 , - 1 , - 1 ):
1733
+ right_max_array [i ] = max (right_max_array [i + 1 ], heights [i ])
1734
+ water = 0
1735
+ for i in range (N ):
1736
+ water += min (left_max_array [i ], right_max_array [i ]) - heights [i ]
1737
+ return water
1738
+
1739
+
1740
+ def test_30 ():
1741
+ assert totalTrappedWater ([2 , 1 , 2 ]) == 1
1742
+ assert totalTrappedWater ([3 , 0 , 1 , 3 , 0 , 5 ]) == 8
1743
+
1744
+
1745
+ """
1746
+ question 31
1747
+ The edit distance between two strings refers to the minimum number of character
1748
+ insertions, deletions, and substitutions required to change one string to the
1749
+ other. For example, the edit distance between “kitten” and “sitting” is three:
1750
+ substitute the “k” for “s”, substitute the “e” for “i”, and append a “g”.
1751
+
1752
+ Given two strings, compute the edit distance between them.
1753
+
1754
+ -------------------
1755
+ kitten
1756
+ ^
1757
+ sitting
1758
+ ^
1759
+
1760
+ if c1==c2:
1761
+ i1++ i2++
1762
+ else:
1763
+ a. delete: i1++ -> go right
1764
+ b. insert: i2++ -> go down
1765
+ c. replace: i1++ i2++ -> go right-down
1766
+ steps ++
1767
+
1768
+ DP bottom-up
1769
+ k i t t e n
1770
+ s 1 2 3 4 5 6
1771
+ i 2 1 2 3 4 5
1772
+ t 3 2 1 2 3 4
1773
+ t 4 3 2 1 2 3
1774
+ i 5 4 3 2 2 3
1775
+ n 6 5 4 3 3 2
1776
+ g 7 6 5 4 4 3
1777
+ """
1778
+
1779
+
1780
+ def editDistance (src , dest ):
1781
+ init = 0 if src [0 ] == dest [0 ] else 1
1782
+ pre = list (range (init , init + len (src )))
1783
+ cur = [0 ] * len (src )
1784
+ for i in range (1 , len (dest )):
1785
+ cur [0 ] = pre [0 ] + 1
1786
+ for j in range (1 , len (src )):
1787
+ if src [j ] == dest [i ]:
1788
+ cur [j ] = pre [j - 1 ]
1789
+ else :
1790
+ cur [j ] = min (min (pre [j - 1 ], pre [j ]), cur [j - 1 ]) + 1
1791
+ pre = cur
1792
+ cur = [0 ] * len (src )
1793
+ return pre [len (src ) - 1 ]
1794
+
1795
+
1796
+ def test_31 ():
1797
+ assert editDistance ("kitten" , "sitting" ) == 3
1798
+ assert editDistance ("sigtten" , "sitting" ) == 3
1799
+
1800
+
1462
1801
"""
1463
1802
question 32 TODO
1464
1803
This problem was asked by Jane Street.
0 commit comments