String

[TOC]

Golang中的字符串

golang语言中字符串中所包含的类型

	str := "su"
	for i, s := range str {
		fmt.Printf("i %T, v %T, s[i] %T\n", i, s, str[i]) // int, int32, uint8
	}
	for _, v := range str {
		fmt.Printf("%T \n", v) // int32
	}
	for i := range str {
		fmt.Printf("%T \n", i) // int
	}
byte是uint8的别名, rune是int32的别名。

相关题目

14 Longest Common Prefix【最长公共前缀】

思路分析:

算法1:最长公共前缀一定存在最短的那个字符串中,因此先求出最短的字符串的长度minLen,然后依次比较每个字符串中的第i个字符(0 <= i < minLen),如果相同则追加到结果中,否则退出,返回之前的结果。【垂直扫描】

算法2:水平扫描法,n个字符串的最长公共前缀,一定是前n-1个字符串的最长公共前缀与第n个字符串的公共前缀,即公式LCP(S1...Sn) = LCP(LCP(LCP(S1, S2) S3)...Sn)

// 算法1:直接比较,也称为垂直扫描
func longestCommonPrefix(strs []string) string {
    if len(strs) == 0 {return ""}
    if len(strs) == 1 {return strs[0]}
    // find the minLen
    minLen := 1 << 31 -1
    for _, str := range strs {
        if len(str) < minLen {
            minLen = len(str)
        }
    }
    var res string
    for i:= 0; i < minLen; i++ {
        r := strs[0][i]
        ok := true
        for j := 1; j < len(strs); j++ {
            if r != strs[j][i] {
                ok = false
                break
            }
        }
        if !ok {
            break
        }
        res = res + string(r)
    }
    return res
}

// 算法2: 水平扫描,利用公式LCP(S1...Sn) = LCP(LCP(LCP(S1,S2), S3)...Sn)
func longestCommonPrefix(strs []string) string {
    if len(strs) == 0 { return "" }
    prefix := strs[0]
    for i := 1; i < len(strs); i++ {
        prefix = findPrefix(prefix, strs[i])
        if len(prefix) == 0 {return ""}
    }
    return prefix
}

func findPrefix(s1, s2 string) string {
    minLen := len(s1)
    if len(s2) < minLen {
        minLen = len(s2)
    }
    var res string
    for i := 0; i < minLen; i++ {
        if s1[i] != s2[i] {break}
        res += string(s1[i])
    }
    return res
}

实现strStr()

思路分析

算法1:找到起始点,并判断是否相同。

func strStr(haystack, needle string) int {
  if len(needle) <= 0 {return 0}
  n1, n2 := len(haystack), len(needle)
  for i := 0; i < n1; i++ {
    if haystack[i] != needle[0] {
      continue
    }
    if i + n2 > n1 {
      return -1
    }
    if string(haystack[i:i+n]) == needle {return i}
  }
  return -1
}

151 翻转字符串里的单词

题目要求:

思路分析:

// date 2020/03/29
/*
1. 从字符串尾部开始遍历,依次翻转每个单词
2. 遍历字符串的时候主要去掉多余空格,最后的结果也需要去掉多余的空格
*/
func reverseWords(s string) string {
  res, word_res := make([]byte, 0), make([]byte, 0)
  end := len(s)-1
  // 去掉尾部多余的空格
  for end >= 0 && s[end] == ' ' { end-- }
  for i := end; i >= 0; i-- {
    if s[i] != ' ' {
      word_res = append(word_res, s[i])
    } else {
      // 找到一个单词
      res = append(res, reverseWord(word_res)...)
      res = append(res, ' ')
      // 去掉中间多余的空格
      for i >= 0 && s[i] == ' ' { i-- }
      i++
      word_res = word_res[:0]
    }
  }
  if len(word_res) > 0 {
    res = append(res, reverseWord(word_res)...)
  }
  if len(res) > 0 && res[len(res)-1] == ' ' {
    res = res[:len(res)-1]
  }
  return string(res)
}

func reverseWord(word []byte) []byte {
  i, j := 0, len(word)-1
  var c byte
  for i < j {
    c = word[i]
    word[i] = word[j]
    word[j] = c
    i++
    j--
  }
  return word
}

246 中心对称数

题目要求:https://leetcode-cn.com/problems/strobogrammatic-number/

// date 2020/03/21
func isStrobogrammatic(num string) bool {
    m := map[byte]byte{
        '6': '9',
        '9': '6',
        '8': '8',
        '0': '0',
        '1': '1',
    }
    l, r, n := 0, len(num)-1, len(num)
    for l < r {
        if m[num[l]] == num[r] {
            l++
            r--
        } else {
            return false
        }
    }
    // 如果是奇数个元素
    if n & 0x1 == 1 && m[num[n/2]] != num[n/2] { return false }
    return true
}

345 反转字符串中的元音字母

// date 2019/12/28
// 双指针
func reverseVowels(s string) {
  vs := make([byte]int)
  vs['a'] = 1
  vs['e'] = 1
  vs['i'] = 1
  vs['o'] = 1
  vs['u'] = 1
  vs['A'] = 1
  vs['E'] = 1
  vs['I'] = 1
  vs['O'] = 1
  vs['U'] = 1
  i, j := 0, len(s) - 1
  var temp byte
  for i < j {
    _, ok := vs[s[i]]
    if ok {
      _, ok2 := vs[s[j]]
      if ok2 {
        temp = s[j]
        s[j] = s[i]
        s[i] = temp
        i++
        j--
      } else {
        j--
      }
    } else {
      i++
    }
  }
}

521 最长特殊序列I

题目要求:https://leetcode-cn.com/problems/longest-uncommon-subsequence-i/

思路分析:题意难以理解

// date 2020/03/08
func findLUSlength(a, b string) int {
  if a == b { return len(a) }
  if len(a) == len(b) || len(a) > len(b) { return len(a) }
  return len(b)
}

576 字符串的排列

题目要求:https://leetcode-cn.com/problems/permutation-in-string/

思路分析:

// date 2020/03/28
/*
1. 注意题目要求,字符串问题很多都可以使用数组,好处就是golang中数组可以直接比较的
2. 第一个字符串的排列之一是第二个字符串的子串,所以字符出现的顺序很重要
*/
func checkInclusion(s1 string, s2 string) bool {
    if len(s1) > len(s2) { return false }
    // 题目中只包含小写字母,所以使用数组更方便[26]int
    var s1map [26]int
    for _, c := range s1 { s1map[c - 'a']++ }
    for i := 0; i <= len(s2)-len(s1); i++ {
        var s2map [26]int
        for j := 0; j < len(s1); j++ {
            s2map[s2[i+j] - 'a']++
        }
        if s1map == s2map { return true }
    }
    return false
}

594 最长和谐子序列

题目要求:https://leetcode-cn.com/problems/longest-harmonious-subsequence/

算法分析

// date 2020/03/08
// 算法一:两层循环,超时
// 算法二:利用map,时间复杂度O(N),空间复杂度O(N)
func findLHS(nums []int) int {
  m := make(map[int]int, 0)
  for _, v := range nums {
    if _, ok := m[v]; ok {
      m[v]++
    } else {
      m[v] = 1
    }
  }
  res := 0
  for k, v1 := range m {
    if v2, ok := m[k+1]; ok && v1+v2 > res { res = v1+v2 }
  }
  return res
}
// 算法三,算法二的优化版
func findLHS(nums []int) int{
  res, m := 0, make(map[int]int, 0)
  for _, v := range nums {
    if _, ok := m[v]; ok {
      m[v]++
    } else {
      m[v] = 1
    }
    // cal
    if v1, ok := m[v-1]; ok && m[v]+v1 > res { res = v1+m[v] }
    if v1, ok := m[v+1]; ok && m[v]+v1 > res { res = v1+m[v] }
  }
  return res
}

674 最长连续递增序列

题目要求:https://leetcode-cn.com/problems/longest-continuous-increasing-subsequence/

算法分析:

// date 2020/03/08
func findLengthOfLCIS(nums []int) int {
  if len(nums) == 0 { return 0 }
  res, temp := 1, 1
  for i := 0; i < len(nums)-1; i++ {
    if nums[i+1] > nums[i] {
      temp++
    } else {
      temp = 1
    }
    if temp > res { res = temp }
  }
  return res
}

字符串中第一个唯一的字符

func firstUniqChar(s string) int {
  m := make(map[uint8]int, len(s))
  for i := 0; i < len(s); i++ {
    if _, ok := m[s[i]]; ok {
      m[s[i]] = -1
    } else {
      m[s[i]] = i
    }
  }
  for i := 0; i < len(s); i++ {
    if v, ok := m[s[i]]; ok && v != -1 {
      return v
    }
  }
  return -1
}

翻转字符串里的单词

题目要求:给定一个字符串,返回其按单词翻转,并去除多余空格的结果。

算法:从字符串的尾部遍历,找到单个单词,并翻转放入其结果,注意空格。

// date 2020/02/02
func reverseWords(s string) string {
  res, temp := make([]byte, 0), make([]byte, 0) // 存放结果和单个单词
  end := len(s)-1
  for end >= 0 && s[end] == ' ' { end-- }
  for i := end; i >= 0; i-- {
    if s[i] != ' ' {
      temp = append(temp, s[i])
    } else {
      // find the word
      res = append(res, reverseWord(temp)...)
      res = append(res, ' ')
      for i >= 0 && s[i] == ' ' { i-- }
      i++
      temp = make([]byte, 0)
    }
  }
  if 0 != len(temp) {
    res = append(res, reverseWord(temp)...)
  }
  if len(res) > 0 && res[len(res)-1] == ' ' {
    res = res[:len(res)-1]
  }
  return string(res[:len(res)])
}
func reverseWord(word []byte) []byte {
  s, e := 0, len(word)-1
  var t byte
  for s < e {
    t = word[s]
    word[s] = word[e]
    word[e] = t
    s++
    e--
  }
  return word
}

820 单词的压缩编码

题目要求:https://leetcode-cn.com/problems/short-encoding-of-words/

思路分析:考察知识点,字典树

如果一个单词是另一个单词的后缀,则该单词不需要重新编码。

// date 2020/03/28
func minimumLengthEncoding(words []string) int {
  // 将单词存入哈希表,方便删除
  set := make(map[string]string, len(words))
  for _, w := range words {
    set[w] = w
  }
  // 查找可能存在的单词后缀,并删除它,注意单词的索引从1开始
  for _, word := range words {
    for i := 1; i < len(word); i++ {
      key := string(word[i:])
      if _, ok := set[key]; ok {
        delete(set, key)
      }
    }
  }
  // 统计并返回结果
  var res int
  for word := range set {
    res += len(word)+1
  }
  return res
}

最后更新于