[leetcode] Partition Labels

A string S of lowercase letters is given. We want to partition this string into as many parts as possible so that each letter appears in at most one part, and return a list of integers representing the size of these parts.

 

Example 1:

Input: S = "ababcbacadefegdehijhklij"
Output: [9,7,8]
Explanation:
The partition is "ababcbaca", "defegde", "hijhklij".
This is a partition so that each letter appears in at most one part.
A partition like "ababcbacadefegde", "hijhklij" is incorrect, because it splits S into less parts.

 

Note:

  1. S will have length in range [1, 500].
  2. S will consist of lowercase letters ('a' to 'z') only.

分析:题目翻译一下:给定一个字符串,要求将字符串分片,使得每一片中出现的字符仅在这个分片中出现。
第一个思路:用一map保存每个字符串出现的次数,如果走到某个字符处,前面所有字符对应的值都为0,那么就说明这个分片找到了。根据这个原理,可以写出下面代码:
 1 class Solution {
 2     public List<Integer> partitionLabels(String S) {
 3         Map<Character,Integer> map = new HashMap<>();
 4         Set<Character> set = new HashSet<>();
 5         List<Integer> list = new ArrayList<>();
 6 
 7         for ( char c : S.toCharArray() )
 8             map.put(c,map.getOrDefault(c,0)+1);
 9         //System.out.println(map);
10 
11         int left = 0;
12         int count = 0;
13         while ( left < S.length() ){
14             char c = S.charAt(left);
15             set.add(c);
16             map.put(c,map.get(c) - 1);
17             count += 1;
18             boolean ise = true;
19             for ( char temp : set ){
20                 if ( map.get(temp) != 0 ) ise = false;
21             }
22             if ( ise ){
23                 list.add(count);
24                 count = 0;
25                 set.clear();
26             }
27             left ++;
28         }
29         return list;
30     }
31 }

    运行时间42ms,非常耗时。不过这个方法是最直观的方法。下面分析如何改进。

第二个思路:上一个方法是不停的对map进行-1操作,然后判断是否为0。这个题目也可以用map来保存每个字符最后出现的位置,并且用一个变量保存前面出现过的字符中最远的位置。如果cur指针走到这个位置,就说明前面的都被访问过了,就得到了这个分片。show me the code:

 1 class Solution {
 2     public List<Integer> partitionLabels(String S) {
 3         Map<Character,Integer> map = new HashMap<>();
 4         List<Integer> list = new ArrayList<>();
 5         
 6         for ( int i = 0 ; i < S.length() ; i ++ )
 7             map.put(S.charAt(i),i);
 8 
 9         int left = 0, right = 0, cur = 0;
10         while ( cur < S.length() ){
11             char c = S.charAt(cur);
12             right = Math.max(right,map.get(c));
13             if ( cur == right ){
14                 list.add(right-left+1);
15                 left = right+1;
16             }
17             cur++;
18         }
19         return list;
20     }
21 }

  运行时间14ms,击败36.70%,还是很慢。为什么呢?

第三个思路:其实也不散完整的思路,对上面进行改进,因为map工作量比较大,因此不妨用一个26长度的数组取代map(这个方法在用到map和字符串的时候非常常见)。

 1 class Solution {
 2     public List<Integer> partitionLabels(String S) {
 3         List<Integer> list = new ArrayList<>();
 4         int[] a = new int[26];
 5         for ( int i = 0 ; i < S.length() ; i ++ )
 6             a[S.charAt(i)-'a'] = i;
 7 
 8         int left = 0, right = 0, cur = 0;
 9         while ( cur < S.length() ){
10             char c = S.charAt(cur);
11             right = Math.max(right,a[c-'a']);
12             if ( cur == right ){
13                 list.add(right-left+1);
14                 left = right+1;
15             }
16             cur++;
17         }
18         return list;
19     }
20 }

  运行时间12ms,击败52.83%。已经尽力了。。

 

总结:关键在于想到map中保存每个字符最后出现的次数,并且在循环过程中如何判断是否满足分片条件。

posted @ 2018-10-02 14:01  Lin.B  阅读(169)  评论(0编辑  收藏  举报