Sunday, November 4, 2018

936. Stamping The Sequence


[2ND TRY]
Version #3 Greedy without any reason

class Solution {
    private int matchedCount;
public int[] movesToStamp(String stamp, String target) {
char[] chars = target.toCharArray();
matchedCount = 0;
List<Integer> result =new LinkedList<>();
while(matchedCount != target.length()) {
if (!match(stamp, target, chars, result)) break;
}
return matchedCount == target.length() ? result.stream().mapToInt(a -> a).toArray() : new int[0];
}

private boolean match(String stamp, String target, char[] chars, List<Integer> result) {
for (int i = 0; i <= target.length() - stamp.length(); i++) {
int j = 0;
boolean canMatch = false;
for (j = 0; j < stamp.length(); j++) {
if (chars[i + j] == stamp.charAt(j)) {
canMatch = true;
} else if (chars[i + j] != '?') {
break;
}
}
if (canMatch && j == stamp.length()) {
for (j = 0; j < stamp.length(); j++) {
if (chars[i + j] != '?') {
chars[i + j] = '?';
matchedCount++;
}
}
result.add(0, i);
return true;
}
}
return false;
}
}


Version #2 TLE BFS
public int[] movesToStamp(String stamp, String target) {
String mask = "";
String result = "";
int stampLen = stamp.length();
for (int i = 0; i < stampLen; i++) mask += "?";
for (int i = 0; i < target.length(); i++) result += "?";
// key-string after stamped like ababc -> ab???, value-list of indexed where we have put stamps
Map<String, List<Integer>> map = new HashMap<>();
// string[0] places we can still put stamp, string[1] target
Queue<String> que =new LinkedList<>();
que.offer(target);
int step = 0;
while (!que.isEmpty()) {
step++;
if (step > 10) return new int[0];
int size = que.size();
while (size-- > 0) {
String curr = que.poll();
List<Integer> stamped = map.getOrDefault(curr, new ArrayList<>());
// ab???, [2]
for (int i = 0; i <= target.length() - stampLen; i++) {
if (stamped.contains(i)) continue; // skip if we have already stamped on this position
int j = 0;
boolean valid = false;
for (j = 0; j < stampLen; j++) {
if (stamp.charAt(j) == target.charAt(i + j)) {
valid = true; // this stamp contributes to our result
} else if (curr.charAt(i + j) != '?') {
break;
}
}
if (valid && j == stampLen) { // we can stamp here
String next = curr.substring(0, i) + mask + curr.substring(i + stampLen);
List<Integer> nextStamped = new LinkedList<>(stamped);
nextStamped.add(0, i);
if (next.equals(result)) return nextStamped.stream().mapToInt(a -> a).toArray();
if (!map.containsKey(next)) {
map.put(next, nextStamped);
que.offer(next);
}
}
}
}
}
return new int[0];
}


[1ST TRY]
一个非常有意思的题
怎么说,中心思想感觉上非常像topological sort
用一个stamp的start index来表示 distinct stamp
一开始默认为targe从0 一直到 targetLen - stampLen 都会有潜在的stamp可以盖章
我们希望当一个stamp落下的时候,它的所有character都和target是matched
所以当我们用 O(targetLen*stampLen)搜索整个target,找到所有character完全match的stamp,就可以把它们放入我们的done queue里面,代表这些位置是可以盖章的
那么盖章以后的效果是什么呢,就是使盖章的char完全满足target, 并且覆盖之前不满足的任何char

 stamp = "abca", target = "aabcaca"
//       stamp     a b c a
//       target      a a b c a c a     
//       matched     todo
        // 0 ->  0           1 2 3
        // 1 ->  1 2 3 4
        // 2 ->              2 3 4 5
        // 3 ->  3 4         5 6
        // use index i to represent where to put stamp
譬如当我们在 index=2盖章后,就完全使整个[index, index + stampLen) 满足条件
整个区域都可以在boolean[] visited 里面设为true
我们找哪些 stamp 的todo list里面有这些点,就可以把他们移除掉,因为后面的stamp 帮助他们完成了这些点
如果这些候选的stamp 的todo list 空了,有两种情况
重点!!!
1. 虽然它的todo list空了,但是它有些点是自己的matched点,也就是说需要盖下这个章才能满足
2.其他的stamp帮它完成了它的任务,在他的范围内所有char都已经盖完了,那么这个stamp就不需要盖章了
具体是1还是2,要在我们位于stamp的时候扫一遍它的范围,看看有没有visited[p] == false
如果有的话,要push到done里面去等待该站,如果没有就完全不用管了

while停止的条件是done的list全部pop完,也就是说该盖的章全都盖上
这里有个bug就是下面这种情况
最后能盖的章都盖完了,还有很多没有解决的点,证明没有可行解,要返回new int[0]

"mda"
"mdadddaaaa"
时间复杂度大约是 O(MN) 的量级

class Solution {
    public int[] movesToStamp(String stamp, String target) {
        Deque<Integer> result = new ArrayDeque<>();
        int stampLen = stamp.length();
        int targetLen = target.length();
        Map<Integer, Set<Integer>> todo = new HashMap<>();
        Queue<Integer> done = new LinkedList<>();
        for (int i = 0; i <= targetLen - stampLen; i++) {
            Set<Integer> todoIndex = new HashSet<>();
            for (int j = 0; j < stampLen; j++) {
                if (stamp.charAt(j) != target.charAt(i + j)) {
                    todoIndex.add(i + j);
                }
            }
            if (todoIndex.isEmpty()) {
                done.offer(i);
            } else {
                todo.put(i, todoIndex);
            }
        }
        boolean[] visited = new boolean[targetLen];
        while (!done.isEmpty()) {
            // p + stampLen = i
            // p = i - stampLen + 1
            //  i   (i+stampLen)
         
            //     abca
            //    aabcaca
            int curr = done.poll();
            result.addFirst(curr);
            // System.out.println("curr -> "  + curr);
            for (int changedPos = curr; changedPos < curr + stampLen; changedPos++) {
                visited[changedPos] = true;
             
                // check all stamp that might contain changedPos
                for (int stampIndex = Math.max(0, curr - stampLen + 1); stampIndex < Math.min(curr + stampLen, targetLen); stampIndex++) {
                    Set<Integer> todoIndex = null;
                    if ((todoIndex = todo.get(stampIndex)) != null) {
                        if (todoIndex.contains(changedPos)) {
                            todoIndex.remove(changedPos);
                            if (todoIndex.size() == 0) {
                                todo.remove(stampIndex);
                                for (int p = 0; p < stampLen; p++) {
                                 
                                    if (!visited[stampIndex + p]) {
                                        done.offer(stampIndex);
                                        break;
                                    }
                                }
                            }
                        }
                    }
                 
                }
            }
        }
        for (boolean visit : visited) {
            if (!visit) {
                return new int[0];
            }
        }
        return result.stream().mapToInt(i -> i).toArray();
    }
}









No comments:

Post a Comment