Skip to content

Commit ea5ba12

Browse files
committed
resolve question 28,29,30,31
1 parent 7872628 commit ea5ba12

File tree

5 files changed

+411
-1
lines changed

5 files changed

+411
-1
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
note.md
22
__pycache__/
33
venv/
4+
*play.py
5+
stats/

first50.py

Lines changed: 340 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1458,7 +1458,346 @@ def test_25():
14581458
assert not regexMatched("*a.", "blablablaay")
14591459

14601460

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+
14621801
"""
14631802
question 32 TODO
14641803
This problem was asked by Jane Street.

0 commit comments

Comments
 (0)