763. 划分字母区间(中等)

1. 题目描述

题目中转:763. 划分字母区间
在这里插入图片描述
在这里插入图片描述

2.详细题解

    划分字母片段,要求每个字母仅能出现在一个片段中,划分的片段数要最多。如果没有限制要最多的情况,那么划分一个片段即不划分任何新的片段即可,因此采用贪心策略:每个片段寻找最小的结束下标。
  直观思路: 寻找每个片段最小的结束下标的关键在于如何确保当前片段中的每个字母均已全部出现,因此需要记录每个字符总共出现的次数,当该片段所有字母均已出现即可判断找到最小的结束下标,即方法一:该方法首先需要遍历统计出所有字符出现的次数;其次遍历寻找最小结束下标,需要用到双指针,第一个指针(i)标记当前字符串的索引位置,第二个指针(cur_index)标记当前片段的索引位置。分为以下几种情况:1.新片段开始,当前字符计入片段,更新第一个指针位置移动1位;2.第二个指针cur_index与当前片段长度一致,即寻找到当前片段最小结束下标,第二个指针置为0;3.当前字符存在于当前片段中,减少该字符出现次数,更新第一个指针位置移动1位;4.第二个指针所指字符已全部包含在当前片段时,更新第二个指针位置移动1位;5.否则,当前字符加入当前片段,更新第一个指针位置移动1位。该方法较为直观,但实现有很多小细节,需要仔细区分各种情况的条件
   方法二:该方法不是方法一的直观思路,但却更易理解。对于每一个划分,都需要寻找最小结束下标(即该字符最后一个出现位置的索引),因此首先记录每一个字符最后一次出现位置的索引下标,当遍历一个字符时,即可找到满足该字符条件下最小的结束下标。具体的,使用三指针,一个指针标记当前遍历位置(i),剩下两个双指针标记当前片段的开始(left)与结束位置(right);当遍历一个字符c时,即可更新右指针right为max(right,c的结束位置),当遍历位置i和右指针right相遇时,即当前片段为满足条件的最小片段。

3.代码实现

3.1 Python

# 方法一:
from collections import Counter
class Solution:
    def partitionLabels(self, s: str) -> List[int]:
        word_dict = Counter(s)
        cur_queue = []
        cur_index = 0
        ans = []
        i = 0
        while i < len(s):
            c = s[i]
            if len(cur_queue) == 0:
                cur_queue.append(c)
                word_dict[c] -= 1
                i += 1
            elif len(cur_queue) == cur_index:
                ans.append(len(cur_queue))
                cur_index = 0
                cur_queue = []
            elif c in cur_queue:
                cur_queue.append(c)
                word_dict[c] -= 1
                i += 1
            elif word_dict[cur_queue[cur_index]] == 0:
                cur_index += 1
            else:
                cur_queue.append(c)
                word_dict[c] -= 1
                i += 1
        if len(cur_queue) > 0:
            ans.append(len(cur_queue))
        return ans


在这里插入图片描述

# 方法二
from collections import defaultdict
class Solution:
    def partitionLabels(self, s: str) -> List[int]:
        ans = []
        last_loc = defaultdict(int)
        for i,c in enumerate(s):
            last_loc[c] = i
        
        left, right = 0, 0
        for i,c in enumerate(s):
            right = max(right, last_loc[c])
            if i == right:
                ans.append(right-left+1)
                left = right + 1
        
        return ans

3.2 Java

class Solution {
    public List<Integer> partitionLabels(String s) {
        List<Integer> ans = new ArrayList<>();
        Map<Character, Integer> lastLoc = new HashMap<>();
        
        for (int i = 0; i < s.length(); i++) {
            lastLoc.put(s.charAt(i), i);
        }
        
        int left = 0, right = 0;
        for (int i = 0; i < s.length(); i++) {
            right = Math.max(right, lastLoc.get(s.charAt(i)));
            if (i == right) {
                ans.add(right - left + 1);
                left = right + 1;
            }
        }
        
        return ans;
    }
}

在这里插入图片描述

  执行用时不必过于纠结,对比可以发现,对于python和java完全相同的编写,java的时间一般是优于python的;至于编写的代码的执行用时击败多少对手,执行用时和网络环境、当前提交代码人数等均有关系,可以尝试完全相同的代码多次执行用时也不是完全相同,只要确保自己代码的算法时间复杂度满足相应要求即可,也可以通过点击分布图查看其它coder的code

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

raykingl

你的鼓励将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值