String Question Summary

Common String Method

s.index(x, start, end) # returns smallest i such that s[i]==x.
s.partition
s.strip
s.split
s.index
s.find
s.isalnum
s.isalpha
s.isdigit
s.islower
sep.join(list)
s.count
s.replace
s.startswith
s.endswith
s.swapcase
s.lower
s.upper

ord() # ord('a) == 97
note
there is no
s.sort()

>>> s.sort()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute 'sort'
>>> sorted(s)
['a', 'a', 'd', 'f', 'h', 'h', 'j', 'k', 'k', 'l', 's']

Some edge case of string method:

s.split()

s = 'fhakjhdlksa'
>>> s.split('f')
['', 'hakjhdlksa']
>>> ss = " a "
>>> ss.split()
['a']
>>> ss.split(' ')
['', 'a', '']

>>> ' 1  2   3  '.split()
['1', '2', '3']

s.strip()

>>> ' spacious '.strip()
'spacious'
>>> 'www.example.com'.strip('cmowz.')
'example'

String tricks

Sort a string

''.join(sorted(item))

Sort a list of string


20. Valid Parentheses

Given a string, determine if it is a palindrome, considering only alphanumeric characters and ignoring cases. Need to ignore characters like '.', '@', '*' etc...

    def isValid(self, s):
        stack = []
        dict = {"]":"[", "}":"{", ")":"("}
        for char in s:
            if char in dict.values():
                stack.append(char)
            elif char in dict.keys():
                if stack == [] or dict[char] != stack.pop():
                    return False
            else:
                return False
        return stack == []

165. Compare Version Numbers

This is an example of question that highly optimized by Python's syntax.

The basic idea is to convert version numbers into list of integers, and then compare them index by index.

https://leetcode.com/discuss/45331/2-4-lines-python-3-different-ways

**Solution 1: ** Pad with izip_longest with fillvalue=0

def compareVersion(self, version1, version2): 
    splits = (map(int, v.split('.')) for v in (version1, version2)) 
    return cmp(*zip(*itertools.izip_longest(*splits, fillvalue=0)))

Solution 2:

def compareVersion(self, version1, version2):
    v1, v2 = (map(int, v.split('.')) for v in (version1, version2))
    d = len(v2) - len(v1)
    return cmp(v1 + [0]*d, v2 + [0]*-d)
      # [0]*-3 is still [0]
      # purpose of this list multiplication is align the length of two list
      # cmp can work on list, compare element by element
      # I feel this step is not needed, as cmp anyway do comparison element by element

Solution 3

def compareVersion(self, version1, version2):
        versions1 = [int(v) for v in version1.split(".")]
        versions2 = [int(v) for v in version2.split(".")]
        for i in range(max(len(versions1),len(versions2))):
            v1 = versions1[i] if i < len(versions1) else 0
            v2 = versions2[i] if i < len(versions2) else 0
            if v1 > v2:
                return 1
            elif v1 < v2:
                return -1;
        return 0;

125. Valid Palindrome

def isPalindrome(self, s):
    newS= [i.lower() for i in s if i.isalnum()]
# is.alnum(): Return true if all characters in the string are alphanumeric and there is at least one character, false otherwise.
    return newS == newS[::-1]
def isPalindrome(self, s):
    l, r = 0, len(s)-1
    while l < r:
        while l < r and not s[l].isalnum():
            l += 1
        while l <r and not s[r].isalnum():
            r -= 1
        if s[l].lower() != s[r].lower():
            return False
        l +=1; r -= 1
    return True

38. Count and Say

(ok, ignore this question. not useful )

def countAndSay(self, n):
    s = ['1']
    result = '1'
    # The n-th sequance, input 1 should output '1'
    for i in range(n-1):
        start = 0
        temp = []
        # Process one sequence, scan from start to end
        while start < len(s):
            count = 1
            next = start + 1
            # Scan until s[next] is different
            while next < len(s) and s[start] == s[next]:
                next += 1
                count += 1
            # Get the new items in
            temp.append(str(count))
            temp.append(s[start])
            # Start from next one
            start = next
        # Concatenate list into string, using "," as separator in default 
        result = ''.join(temp)
        s = temp
    return result

58. Length of Last Word

def lengthOfLastWord(self, s):
        A=s.strip() # if no this step, s = "a " will get wrong
        B=A.split(" ") # need to specify " "
        return len(B[-1]) 

I've noticed that a lot of solutions use available library functions that return directly the positions of certain characters or do other operations like "split". I personally don't think that's a good idea. Firstly, these functions take some time and usually involve with iteration through the whole string. Secondly, questions like this one is intended to be a practice of detail implementation, not calling other functions. My solution like below uses only the most basic string operations and probably beats many other solutions which call other existing functions.

// without using build-in function: 
int lengthOfLastWord(const char* s) {
        int len = 0;
        while (*s) {
            if (*s++ != ' ')
                ++len;
            else if (*s && *s != ' ')
                len = 0;

        }
        return len;
}

8. String to Integer (atoi)

Implement atoi to convert a string to an integer. atoi() function only works with string format digits, not alphabets.
Hint: Carefully consider all possible input cases. If you want a challenge, please do not see below and ask yourself what are the possible input cases.
Notes: It is intended for this problem to be specified vaguely (ie, no given input specs). You are responsible to gather all the input requirements up front.

In Python, atoi() is replaced by int() (so don't use int() )

class Solution(object):
    def myAtoi(self, s):
        """
        :type str: str
        :rtype: int
        """
        ###better to do strip before sanity check (although 8ms slower):
        #ls = list(s.strip())
        #if len(ls) == 0 : return 0
        if len(s) == 0 : return 0
        ls = list(s.strip()) # remember this <--- !!!! 
            # list('abc') == ['a','b','c']
        sign = -1 if ls[0] == '-' else 1
        if ls[0] in ['-','+'] : del ls[0]
        ret, i = 0, 0
        while i < len(ls) and ls[i].isdigit() :
            ret = ret*10 + ord(ls[i]) - ord('0') # ord('a') == 97
            i += 1
        return max(-2**31, min(sign * ret,2**31-1))
            # this is the max of python integer range

3. Longest Substring Without Repeating Characters

/**
 * Solution (DP, O(n)):
 * 
 * Assume L[i] = s[m...i], denotes the longest substring without repeating
 * characters that ends up at s[i], and we keep a hashmap for every
 * characters between m ... i, while storing <character, index> in the
 * hashmap.
 * We know that each character will appear only once.
 * Then to find s[i+1]:
 * 1) if s[i+1] does not appear in hashmap
 *    we can just add s[i+1] to hash map. and L[i+1] = s[m...i+1]
 * 2) if s[i+1] exists in hashmap, and the hashmap value (the index) is k
 *    let m = max(m, k), then L[i+1] = s[m...i+1], we also need to update
 *    entry in hashmap to mark the latest occurency of s[i+1].
 * 
 * Since we scan the string for only once, and the 'm' will also move from
 * beginning to end for at most once. Overall complexity is O(n).
 *
 * If characters are all in ASCII, we could use array to mimic hashmap.
 */

int lengthOfLongestSubstring(string s) {
    // for ASCII char sequence, use this as a hashmap
    vector<int> charIndex(256, -1);
    int longest = 0, m = 0;

    for (int i = 0; i < s.length(); i++) {
        m = max(charIndex[s[i]] + 1, m);    // automatically takes care of -1 case
        charIndex[s[i]] = i;
        longest = max(longest, i - m + 1);
    }

    return longest;
}
class Solution:
    # @return an integer
    def lengthOfLongestSubstring(self, s):
        start = maxLength = 0
        usedChar = {}

        for i in range(len(s)):
            if s[i] in usedChar and start <= usedChar[s[i]]:
                start = usedChar[s[i]] + 1
            else:
                maxLength = max(maxLength, i - start + 1)

            usedChar[s[i]] = i

        return maxLength

** Without hash table **
The idea is pretty simple. We iterate thru the list once and we keep a pointer of where the current longest possible substring starts. During the iteration, we check if this last character is contained in the current substring. If so, move the ptr to the first index of the char at the string +1. Everytime we will compare and keep the max value up to date.

Overall time complexity will be O(n^2)

public class Solution {
    public int lengthOfLongestSubstring(String s) {
        if (s.length() <= 1) return s.length();

        int max = 1;
        int ptr = 0;
        for (int i = 1; i< s.length(); i++) {
            // find the first occurence of the char after index ptr
            int index = s.indexOf(s.charAt(i), ptr); 
            if (index < i) { // it means that it is contained in s.substring(ptr, i)
                ptr = index + 1;
            }
            max = Math.max(max, i - ptr + 1);
        }

        return max;
    }
}    
# without dictionary:
def lengthOfLongestSubstring (self, inString):
    chDict=[-1]*256
    start=0
    maxLen=0

    for i in xrange(len(inString)):
        asc=ord(inString[i])
        if chDict[asc]==-1 or chDict[asc]<start:
            chDict[asc]=i
        else:
            if maxLen<i-start:
                maxLen=i-start
            start=chDict[asc]+1
            chDict[asc]=i

    return max(maxLen, len(inString)-start)  

5. Longest Palindromic Substring

Basic thought is simple. when you increase s by 1 character, you could only increase maxPalindromeLen by 1 or 2, and that new maxPalindrome includes this new character. Proof: if on adding 1 character, maxPalindromeLen increased by 3 or more, say the new maxPalindromeLen is Q, and the old maxPalindromeLen is P, and Q>=P+3. Then it would mean, even without this new character, there would be a palindromic substring ending in the last character, whose length is at least Q-2. Since Q-2 would be >P, this contradicts the condition that P is the maxPalindromeLen without the additional character.

So, it becomes simple, you only need to scan from beginning to the end, adding one character at a time, keeping track of maxPalindromeLen, and for each added character, you check if the substrings ending with this new character, with length P+1 or P+2, are palindromes, and update accordingly.

Now, this is O(n^2) as taking substrings and checking palindromicity seem O(n) time.

class Solution:
    # @return a string
    def longestPalindrome(self, s):
        if len(s)==0:
            return 0
        maxLen=1
        start=0
        for i in xrange(len(s)):
            if i-maxLen >=1 and s[i-maxLen-1:i+1]==s[i-maxLen-1:i+1][::-1]:
                start=i-maxLen-1
                maxLen+=2
                continue

            if i-maxLen >=0 and s[i-maxLen:i+1]==s[i-maxLen:i+1][::-1]:
                start=i-maxLen
                maxLen+=1
        return s[start:start+maxLen]
# a not very smart solution
def longestPalindrome(self, s):
    res = ""
    for i in xrange(len(s)):
        # odd case, like "aba"
        tmp = self.helper(s, i, i)
        if len(tmp) > len(res):
            res = tmp
        # even case, like "abba"
        tmp = self.helper(s, i, i+1)
        if len(tmp) > len(res):
            res = tmp
    return res

# get the longest palindrome, l, r are the middle indexes   
# from inner to outer
def helper(self, s, l, r):
    while l >= 0 and r < len(s) and s[l] == s[r]:
        l -= 1; r += 1
    return s[l+1:r]

49. Group Anagrams

????

def anagrams(self, strs):
    dic = defaultdict(list)
    map(lambda item: dic[''.join(sorted(item))].append(item), strs)
    return [x for key in dic.keys() for x in dic[key] if len(dic[key]) > 1]       

This is equivalent to:

def anagrams(self, strs):
    dic = defaultdict(list)
    for item in strs:
        after = ''.join(sorted(item))
        dic[after].append(item)
    ans = []
    for item in dic:
        values = dic[item]
        if len(values) > 1:
            ans.extend(values)
    return ans

14. Longest Common Prefix (S)

# hard to think solution
class Solution:
    # @return a string
    def longestCommonPrefix(self, strs):
        if not strs:
            return ""

        for i, letter_group in enumerate(zip(*strs)):
            if len(set(letter_group)) > 1: 
                # very tricky step: see python notebook example to further understand this !!! 
                # set() will remove duplicate, if there is difference (not common), then len(set(letter_group)) will > 1
                return strs[0][:i]
        else:
            return min(strs) 
# relatively easy to think solution
class Solution:
    # return common prefix for two strings:
    def lcp(self, str1, str2):
        i = 0
        while (i < len(str1) and i < len(str2)):
            if str1[i] == str2[i]:
                i = i+1
            else:
                break
        return str1[:i]

    # @return a string   
    # return common prefix for all strings
    # build upon the common prefix for two strings:                                                                                                                                                       
    def longestCommonPrefix(self, strs):
        if not strs:
            return ''
        else:
            return reduce(self.lcp,strs) # remember this trick:
                # use reduce function to roll over all the element

6. ZigZag Conversion

remember this solution

class Solution(object):
    def convert(self, s, numRows):
        """
        :type s: str
        :type numRows: int
        :rtype: str
        """
        if numRows == 1 or numRows >= len(s):
            return s

        L = [''] * numRows  # list
        index, step = 0, 1

        for x in s:
            L[index] += x
            if index == 0:
                step = 1
            elif index == numRows -1:
                step = -1
            index += step

        return ''.join(L)  # list -> string

67. Add Binary

Both input and return are binary string.

if int() and bin() function is allowed:

def addBinary(self, a, b):
        a = int(a, 2) # convert binary string into decimal integer
        b = int(b, 2)
        return ("" + bin(a+b))[2:] # bin() convert decimal integer into binary string, with leading '0b'

Iterative without using int():

# iterative backward:
def addBinary(self, a, b):
    res, carry = '', 0
    i, j = len(a) - 1, len(b) - 1
    while i >= 0 or j >= 0 or carry:
        curval = (i >= 0 and a[i] == '1') + (j >= 0 and b[j] == '1')
        # Cool !! 
        carry, rem = divmod(curval + carry, 2)
        # return a pair of numbers consisting of their quotient and remainder when using long division
        res = `rem` + res
        i -= 1
        j -= 1
    return res 

Another iterative without int(), easy to understand:

    def addBinary(self, a, b):
        i, m, n, result, carry = 1, len(a), len(b), [], 0
        while i <= m or i <= n:
            temp = carry
            if i <= m:
                temp += int(a[-i])
            if i <= n:
                temp += int(b[-i])

            carry = temp / 2
            result.append(str(temp % 2))
            i += 1

        if carry:
            result.append(str(carry))

        return ''.join(result[::-1]) 

recursive, without using int():
(remember how this function deal with return in recursion)

class Solution:
# smart approach!! just some manipulation of string
        def addBinary(self, a, b):
            if len(a)==0: return b
            if len(b)==0: return a
            if a[-1] == '1' and b[-1] == '1':
                return self.addBinary(self.addBinary(a[0:-1],b[0:-1]),'1')+'0' # Remember !!! 
            if a[-1] == '0' and b[-1] == '0':
                return self.addBinary(a[0:-1],b[0:-1])+'0'
            else:
                return self.addBinary(a[0:-1],b[0:-1])+'1'          

28. Implement strStr()

class Solution(object):
    def strStr(self, haystack, needle):
        """
        :type haystack: str
        :type needle: str
        :rtype: int
        """
        # iterative by index, not iterator
        for i in range(len(haystack) - len(needle)+1):
            if haystack[i:i+len(needle)] == needle:
                return i
        return -1

227. Basic Calculator II

This is not as easy as first look

def calculate(self, s):
    if not s:
        return "0"
    stack, num, sign = [], 0, "+"
    for i in xrange(len(s)):
        if s[i].isdigit():
            num = num*10+ord(s[i])-ord("0")
        if (not s[i].isdigit() and not s[i].isspace()) or i == len(s)-1:
            if sign == "-":
                stack.append(-num)
            elif sign == "+":
                stack.append(num)
            elif sign == "*":
                stack.append(stack.pop()*num)
            else:
                tmp = stack.pop()
                if tmp//num < 0 and tmp%num != 0:
                    stack.append(tmp//num+1)
                else:
                    stack.append(tmp//num)
            sign = s[i]
            num = 0
    return sum(stack)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,711评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,932评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,770评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,799评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,697评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,069评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,535评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,200评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,353评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,290评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,331评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,020评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,610评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,694评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,927评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,330评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,904评论 2 341

推荐阅读更多精彩内容