Longhao Zhuo home

layout: post title: "[Coding] Data Structure: List and String"

Data Structure String

Dec 2022 - Charlotte, NC

By Topic

String

Array

By Approach

Greedy Algorithm

last = {c: i for i, c in enumerate(S)}
j = anchor = 0
ans = []
for i, c in enumerate(S):
      j = max(j, last[c])
      if i == j: # j marks the last occurrence of all letters previously seen.
        ans.append(i - anchor + 1)
        anchor = i + 1

Hash Table

ans = set()
if sub not in ans:  ans[sub] = 1; else: ans[sub] += 1;
ans = collections.defaultdict(list)
ans[tuple(sorted(s))].append(s)
_count = collections.Counter(S)
_dict, cnt, ans = {}, 0, []
for i in range(len(S)):
    cnt += 1
    if S[i] not in _dict:
        _dict[S[i]] = _count[S[i]]
    _dict[S[i]] -= 1
    if all(v == 0 for v in _dict.values()):
        ans.append(cnt)
        _dict, cnt = {}, 0

Dynamic Programming

Two Pointers

left, right = 0, len(s) - 1
while left < right:
    s[left], s[right] = s[right], s[left]
    left, right = left + 1, right - 1
left, right =0, 0
_sum, cnt = math.inf, 0
while(right<len(nums)):
    _sum=_sum+nums[p2]
    if _sum<target:
        right += 1
    else:
        cnt  = min(cnt, right - left + 1)
        # Need to walk back nums[right]
        _sum = _sum-nums[left]-nums[right]
        left+= 1

Recursive Programming: Divide and Conquer

Divide and Conquer: different from Binary research in a way that each sub-division would contributes to the final solution. Think about Euro Football Group, Semi-final, Final games.

def Divide(strs: List[str], left_index, right_index) -> str:
      if left_index == right_index:
          return strs[right_index]

      mid = (left_index + right_index)//2
      lcp_left = Solution.Divide(strs, left_index, mid)
      lcp_right = Solution.Divide(strs, mid + 1, right_index)
      return Solution.conquer(lcp_left, lcp_right)
- Conquer: find the common substring between two strings
def conquer(left_string, right_string):
      for i, (l, r) in enumerate(zip(left_string, right_string)):
          if l != r:
              return left_string[:i]
      return min(left_string, right_string, key=len)
- Wrapper:
```python
def longestCommonPrefix(self, strs: List[str]) -> str:
    if not strs:
        return ""
    return Solution.Divide(strs, 0, len(strs) - 1)
```

Recursive Programming

Functions

List

Description Function-1 Function-2 Function-3
sort the list xxx.sort() sorted(xxx)
sort a list of lists xxx.sort(key=lambda x:x[0]) sorted(xxx, key=lambda x: x[0])
sort a list of lists based on a second list [x for _, x in sorted(zip(yyy, xxx))]
insert items to list xxx.append(value) xxx.insert(index, value) xxx.extend(list)
insert lists to list xxx.append(list) xxx.insert(index, list)
delete items from list xxx.remove(value) xxx.pop(index) del xxx[index]
return the idx of a given input such that it splits the sorted list bisect_left(List, value) bisect.bisect_left([1,2,3], 2) ---> 1
return the idx of a given input such that it splits the sorted list bisect_right(List, value) bisect.bisect_right([1,2,3], 2) ---> 2

Set

Description Function-1 Function-2
set: s belongs to t s.issubset(t) s <= t
set: union s.union(t) s | t
set: intersection s.intersection(t) s & t
set: x in s but not in t s.diference(t) s - t

String

Description Function-1 Example
return left-most index of "chars" in string "s" s.find("chars"), scanning from left to right s = "01234567890"; s.find("012") = 0; s.find("0") = 0
return right-most index of "chars" in string "s" s.rfind("chars"), scanning from left to right s = "01234567890"; s.rfind("012") = 0; s.rfind("0") = 10
split a string, "s", to a list of letters s.split() s = "ab c ab"; s.split() = ['ab', 'c', 'ab']
join a list of strings, "s_list" to one string "".join(s_list) s = "".join(['ab', 'c', 'ab']); s = "abcab"
reverse a string reversed = s[::-1] s = "abcab", reversed = "bacba"

Matrix: Traverse

1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
# Below is row scan.
for row in range(4):
      for col in range(4):
        ans.append(dp[row][col])
# column scan: switch row and col in for-loops

Below is to scan from bottom-left to top-right

ans = [[] for _ in range(nrow+ncol-1)] for row in range(nrow): for col in range(ncol): ans[row+col].append(arr[row][col]) ans2 = [] for i in ans: ans2.extend(i)

top-right to bottom left: switching if conditions

- Upper triangular: ```[1, 6, 11, 16, 2, 7, 12, 3, 8, 4]```
- Lower triangular: ```[1, 6, 11, 16, 5, 10, 15, 9, 14, 13]```
```python
for gap in range(4):
    row = 0
    col = row + gap
    while (row >=0) & (row < 4) & (col >= 0) & (col < 4):
       ans.append(dp[row][col])
       row += 1
       col += 1
ans = []
for _sum in range(4):
    for col in range(_sum+1):  
      row  = _sum - col
      ans.append(dp[row][col])

Package: colletions

Functions Outcome or Description
_dict = collections.Counter(nums) collections.Counter("Hello") = Counter({'l': 2, 'H': 1, 'e': 1, 'o': 1})
_dict = collections.defaultdict(int) create a dictionary whose values are integer
_dict = collections.defaultdict(list) create a dictionary whose values are list

Let's recap what we looked at in this explore card: