Lecture -2 Medium String Problems¶
Sort characters by frequency¶
You are given a string s. Return the array of unique characters, sorted by highest to lowest occurring characters. If two or more characters have same frequency then arrange them in alphabetic order.
Input: s = "tree"
Output: ['e', 'r', 't']
Input: s = "raaaajj"
Output: ['a', 'j', 'r']
Approach 1 (Brute Force)¶
- create a freq count of chars as an array
- use sort via custom comparator
def sort_chars(s):
freq_count = []
# 0 - 25 (CAPS)
for i in range(26):
freq_count.append([chr(ord('A') + i), 0])
# 26 - 51 (SMALL)
for i in range(26):
freq_count.append([chr(ord('a') + i), 0])
# 52 - 61 (Numbers)
for i in range(10):
freq_count.append([chr(ord('0') + i), 0])
for ch in s:
if ch.isupper():
idx = ord(ch) - ord('A')
elif ch.islower():
idx = ord(ch) - ord('a') + 26 # Offset by 26 for lowercase
else :
idx = ord(ch) - ord('0') + 52 # Offset by 52 for digits
freq_count[idx][1] += 1
freq_count.sort(key=lambda x: (-x[1], x[0]))
result = [ch for ch, count in freq_count if count > 0]
return result
print(sort_chars("tree"))
print(sort_chars("raaaajj"))
print(sort_chars("Aabb"))
['e', 'r', 't'] ['a', 'j', 'r'] ['b', 'A', 'a']
Approach 2 (Cleaner)¶
def sort_chars(s):
CHAR_COUNT = 26 + 26 + 10
freq_count = [["",0] for _ in range(CHAR_COUNT)]
for ch in s:
if ch.isupper():
idx = ord(ch) - ord("A")
elif ch.islower():
idx = ord(ch) - ord("a") + 26
else:
idx = ord(ch) - ord("0") + 52
freq_count[idx][0] = ch
freq_count[idx][1] +=1
freq_count.sort(key=lambda x:(-x[1],x[0]))
result = [ch for ch, count in freq_count if count >0]
return result
print(sort_chars("tree"))
print(sort_chars("raaaajj"))
print(sort_chars("Aabb"))
['e', 'r', 't'] ['a', 'j', 'r'] ['b', 'A', 'a']
Complexity¶
O(N + k log k) : N = len(s) and K = 62 max
O(1) :
Maximum Nesting Depth of Parenthesis¶
Given a valid parentheses string s, return the nesting depth of s. The nesting depth is the maximum number of nested parentheses.
Input: s = "(1+(2*3)+((8)/4))+1"
Output: 3
Input: s = "(1)+((2))+(((3)))"
Output: 3
Appraoch 1 (Use levels)¶
def max_depth(s):
level =0
result =0
for ch in s :
if ch == "(":
level +=1
result = max(result,level)
elif ch == ")":
level -=1
return result
print(max_depth("(1+(2*3)+((8)/4))+1"))
print(max_depth("(1)+((2))+(((3)))"))
3 3
Complexity¶
O(N) : N = len(s)
O(1)
Roman Numerals to Integer¶
Roman numerals are represented by seven different symbols: I = 1, V = 5, X = 10, L = 50, C = 100, D = 500, M = 1000 For example: 2 is written as II, 12 is written as XII, 27 is written as XXVII.
Roman numerals are usually written largest to smallest from left to right. But in six special cases, subtraction is used instead of addition: I before V or X → 4 and 9, X before L or C → 40 and 90, C before D or M → 400 and 900 Given a Roman numeral, convert it to an integer.
Example 1:
Input: s = "LVIII"
Output: 58
Explanation: L = 50, V= 5, III = 3.
Example 2:
Input: s = "MCMXCIV"
Output: 1994
Explanation: M = 1000, CM = 900, XC = 90 and IV = 4.
Approach1 (Brute Force)¶
- First we will build a map for each roman symbol to int value
- Now for handling the subtractve case
- If the next char is greater in value then current char , we need to subtract it
- other wise add it
def roman_to_int(s):
value_map = {
"I" : 1,
"V" : 5,
"X":10,
"L":50,
"C":100,
"D":500,
"M":1000
}
n = len(s)
result =0
for i in range(n):
if i+1 < n and value_map[s[i]] < value_map[s[i+1]]:
result -= value_map[s[i]]
else:
result +=value_map[s[i]]
return result
print(roman_to_int("LVIII"))
print(roman_to_int("MCMXCIV"))
print(roman_to_int("III"))
print(roman_to_int("IV"))
58 1994 3 4
Complexity¶
O(N) : N = len(s)
O(1)