2021-08-31:去除重复字母。给你一个字符串 s ,请你去除字符串中重复的字母,使得每个字母只出现一次。需保证 返回结果的字典序最小(要求不能打乱其他字符的相对位置)。力扣316。

Posted 福大大架构师每日一题

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021-08-31:去除重复字母。给你一个字符串 s ,请你去除字符串中重复的字母,使得每个字母只出现一次。需保证 返回结果的字典序最小(要求不能打乱其他字符的相对位置)。力扣316。相关的知识,希望对你有一定的参考价值。

2021-08-31:去除重复字母。给你一个字符串 s ,请你去除字符串中重复的字母,使得每个字母只出现一次。需保证 返回结果的字典序最小(要求不能打乱其他字符的相对位置)。力扣316。

福大大 答案2021-08-31:

k种字符。
时间复杂度:O(k*N)。
空间复杂度:O(k)。

代码用golang编写。代码如下:

package main

import (
    "fmt"
    "strings"
)

func main() {
    str := "abcdea"
    ret := removeDuplicateLetters1(str)
    fmt.Println(ret)
    ret = removeDuplicateLetters2(str)
    fmt.Println(ret)
}

// 在str中,每种字符都要保留一个,让最后的结果,字典序最小 ,并返回
func removeDuplicateLetters1(str string) string {
    if len(str) < 2 {
        return str
    }
    map0 := make([]int, 256)
    for i := 0; i < len(str); i++ {
        map0[str[i]]++
    }
    minACSIndex := 0
    for i := 0; i < len(str); i++ {
        if str[minACSIndex] > str[i] {
            minACSIndex = i
        }
        map0[str[i]]--
        if map0[str[i]] == 0 {
            break
        }
    }
    // 0...break(之前) minACSIndex
    // str[minACSIndex] 剩下的字符串str[minACSIndex+1...] -> 去掉str[minACSIndex]字符 -> s'
    // s'...
    return fmt.Sprintf("%c", str[minACSIndex]) + strings.ReplaceAll(str[minACSIndex+1:], fmt.Sprintf("%c", str[minACSIndex]), "")
}

func removeDuplicateLetters2(s string) string {
    // 小写字母ascii码值范围[97~122],所以用长度为26的数组做次数统计
    // 如果map[i] > -1,则代表ascii码值为i的字符的出现次数
    // 如果map[i] == -1,则代表ascii码值为i的字符不再考虑
    map0 := make([]int, 26)
    for i := 0; i < len(s); i++ {
        map0[s[i]-'a']++
    }
    res := make([]byte, 26)
    index := 0
    L := 0
    R := 0
    for R != len(s) {
        // 如果当前字符是不再考虑的,直接跳过
        // 如果当前字符的出现次数减1之后,后面还能出现,直接跳过
        ok := false
        if !ok {
            ok = map0[s[R]-'a'] == -1
        }
        if !ok {
            map0[s[R]-'a']--
            ok = map0[s[R]-'a'] > 0
        }
        if ok {
            R++
        } else { // 当前字符需要考虑并且之后不会再出现了
            // 在str[L..R]上所有需要考虑的字符中,找到ascii码最小字符的位置
            pick := -1
            for i := L; i <= R; i++ {
                if map0[s[i]-'a'] != -1 && (pick == -1 || s[i] < s[pick]) {
                    pick = i
                }
            }
            // 把ascii码最小的字符放到挑选结果中
            res[index] = s[pick]
            index++
            // 在上一个的for循环中,str[L..R]范围上每种字符的出现次数都减少了
            // 需要把str[pick + 1..R]上每种字符的出现次数加回来
            for i := pick + 1; i <= R; i++ {
                if map0[s[i]-'a'] != -1 { // 只增加以后需要考虑字符的次数
                    map0[s[i]-'a']++
                }
            }
            // 选出的ascii码最小的字符,以后不再考虑了
            map0[s[pick]-'a'] = -1
            // 继续在str[pick + 1......]上重复这个过程
            L = pick + 1
            R = L
        }
    }
    return string(res[0:index])
}

执行结果如下:


左神java代码

以上是关于2021-08-31:去除重复字母。给你一个字符串 s ,请你去除字符串中重复的字母,使得每个字母只出现一次。需保证 返回结果的字典序最小(要求不能打乱其他字符的相对位置)。力扣316。的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode #316 去除重复字母

LeetCode 0316. 去除重复字母:单调栈

字符串字母的排列:如何去除重复排列?

LeetCode——不同字符的最小子序列/去除重复字母

leetcode——316. 去除重复字母

js获取一个字符串中字母的个数