边工作边刷题:70天一遍leetcode: day 96-2

Rearrange String k Distance Apart

要点:这题要反向思维:如果k distance apart,那么除非最后一组,其他k组都是distinct的。greedy algorithm:显然出现次数越多,越要优先放,这样才能分布到尽可能多个streak。另外同个char最好间隔正好k。

  • 二个考虑的问题:如何按次数一个streak一个streak generate?什么情况不够条件了返回?
    • 如果每个streak都是distinct的,那么下一个放的元素要出heap,如果count不为0,再入heap来放下一个streak:这就类似level order traversal了,只不过当前层的遍历是固定的k
    • 显然heap中(当前层)元素不够了,就说明不满足条件了

python coding

  • python要用collections.Counter()来计数,不要loop了,产生Counter object,用items()来产生一个(key,count) pair list

https://repl.it/CaPy
另一种解法:上面的heapq解法是每个bucket一起填充,所以不断出heap再入heap。而另一种解法是优先把某个letter填到不同的bucket里。

  • component包括:nbins,idx list(用来标注每个bin填充的位置)。

  • 公式:

    • bucket是轮流填充的,所以bucket的i公式i=(i+1)%nbins
    • nbins:(len-1)/k+1:死记,同时可以兼顾奇偶的情况
  • greedy的两点考虑:显然如果某个letter个数超过nbins,不符合。同时可能某个bin已经满了,所以新letter要放到下一个中。所以即使不同letter的个数超过k也可能。有可能其他都满了,发现最后只能和上一个重复letter放在同一个bucket里,这样也不符合。

  • https://repl.it/CaPy/1

  • 错误点

    • 公式2.1是%nbins,不是k
    • 检查是否同一个bucket要用idx[i]-1而不是idx[i-1]
    • Counter排序需要reverse
import collections
from heapq import *

class Solution(object):

    def rearrangeString(self, str, k):
        """
........:type str: str
........:type k: int
........:rtype: str
........"""

        lettercounts = collections.Counter(str)
        countheap = []
        for c, count in lettercounts.items():
            heappush(countheap, (-count, c))
        n = len(str)
        res = []
        while countheap:
            ln = min(k, n)
            nextround = []
            for i in xrange(ln):
                if not countheap:
                    return ""
                count, c = heappop(countheap)
                count+=1 # b/c count is negative 
                if count<0:
                	nextround.append((count, c))
                res.append(c)
                n -= 1
			
            for count, c in nextround:
                heappush(countheap, (count, c))
        return ''.join(res)
        
s = Solution()
# "abacabcd"
print s.rearrangeString("aaadbbcc", 2)
# ""
print s.rearrangeString("aaabc", 3)
# "abcabc"
print s.rearrangeString("aabbcc", 3)
        
# Given a non-empty string str and an integer k, rearrange the string such that the same characters are at least distance k from each other.

# All input strings are given in lowercase letters. If it is not possible to rearrange the string, return an empty string "".

# Example 1:
# str = "aabbcc", k = 3

# Result: "abcabc"

# The same letters are at least distance 3 from each other.
# Example 2:
# str = "aaabc", k = 3 

# Answer: ""

# It is not possible to rearrange the string.
# Example 3:
# str = "aaadbbcc", k = 2

# Answer: "abacabcd"

# Another possible answer is: "abcabcda"

# The same letters are at least distance 2 from each other.
# Credits:
# Special thanks to @elmirap for adding this problem and creating all test cases.

# Hide Company Tags Google
# Hide Tags Hash Table Heap Greedy

from collections import Counter

class Solution(object):
    def rearrangeString(self, str, k):
        """
        :type str: str
        :type k: int
        :rtype: str
        """
        if k==0:return str
        n = len(str)
        nbins = (n-1)/k+1
        def binsize(i, k, n):
            return min(k, n-i*k)
        
        counts = Counter(str).items()
        counts.sort(key=lambda x: x[1], reverse=True) # error 3: should be reverse order
        idx = [0]*nbins
        i = 0
        res = ['']*n
        for c, m in counts:
            if m>nbins:
                return ""
            
            for _ in xrange(m):
                while idx[i]>=binsize(i, k, n):
                    i = (i+1)%nbins # error 1: nbins, not k
                offset = i*k
                # print i, offset, idx[i]
                if idx[i]>0 and res[offset + idx[i]-1]==c: # error 2: idx[i]-1 not idx[i-1], i is bucket number
                    return ""
                
                res[offset+idx[i]]=c
                idx[i]+=1
                i = (i+1)%nbins
        # print res
        return ''.join(res)
        
s = Solution()
# "abacabcd"
assert s.rearrangeString("aaadbbcc", 2)=="acababcd"
# ""
assert s.rearrangeString("aaabc", 3)==""
# "acbacb"
assert s.rearrangeString("aabbcc", 3)=="acbacb"

posted @ 2016-07-08 20:41  absolute100  阅读(126)  评论(0编辑  收藏  举报