魔术排列
难度:
标签:
题目描述
English description is not available for the problem. Please switch to Chinese.
代码结果
运行时间: 28 ms, 内存: 16.7 MB
/*
* 思路:
* 1. 初始排列为1到N。
* 2. 对于每个可能的k值(1到N),模拟洗牌过程。
* 3. 每次将偶数位置的牌放到奇数位置前面,取走前k张卡牌。
* 4. 记录取走卡牌的顺序,检查是否与target一致。
* 5. 如果找到匹配的k值,返回true;否则返回false。
*/
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class MagicShuffleStream {
public boolean isMagic(int[] target) {
int N = target.length;
int[] original = IntStream.rangeClosed(1, N).toArray();
return IntStream.rangeClosed(1, N)
.anyMatch(k -> isMagicWithK(target, original, k));
}
private boolean isMagicWithK(int[] target, int[] original, int k) {
List<Integer> deck = Arrays.stream(original).boxed().collect(Collectors.toList());
List<Integer> sequence = new ArrayList<>();
while (!deck.isEmpty()) {
List<Integer> even = IntStream.range(0, deck.size())
.filter(i -> i % 2 == 0)
.mapToObj(deck::get)
.collect(Collectors.toList());
List<Integer> odd = IntStream.range(0, deck.size())
.filter(i -> i % 2 != 0)
.mapToObj(deck::get)
.collect(Collectors.toList());
deck.clear();
deck.addAll(even);
deck.addAll(odd);
sequence.addAll(deck.subList(0, Math.min(k, deck.size())));
deck = deck.subList(Math.min(k, deck.size()), deck.size());
}
return IntStream.range(0, target.length)
.allMatch(i -> sequence.get(i) == target[i]);
}
}
解释
方法:
该题解通过首先确定可能的k值来检验是否可以通过特定的洗牌方法和取数顺序生成目标数组target。首先生成一个从1到N的数组,然后模拟魔术师的洗牌方法(将偶数位置的卡片放到奇数位置卡片的前面),以此来判定在第一次洗牌后的数组中,最长的和target数组前缀匹配的长度,即为k。接下来,使用这个k值,通过重复洗牌和截取操作来尝试构建一个和target相同的序列。如果通过这种方式完全构建的序列和target相同,返回true;否则,返回false。
时间复杂度:
O(n log_k(n))
空间复杂度:
O(n)
代码细节讲解
🦆
在定义函数isMagic时,你是如何确定洗牌的初始数组应该是从1到N的顺序?是否可以考虑使用其他的初始排列?
▷🦆
在寻找最长的和target数组前缀匹配的长度k时,你是如何确保这个k值在后续的洗牌过程中仍然有效?
▷🦆
当k值非常小,例如k=1时,这种方法的效率如何?是否会显著影响算法的性能?
▷