在接受采访时被问及
"What is the most efficient way to implement a shuffle function in a music
player to play random songs without repetition"
我建议使用链接列表方法,即使用链接列表,生成随机数并从列表中删除该项目/歌曲(这样,我们确保不会重复播放歌曲)
然后我提出了位向量方法但他并不满意。
那么根据你是实现这种功能的最佳方法呢?
答案 0 :(得分:1)
没有完美的答案,我想这类问题的目的是开始讨论。很可能你的面试官想要了解Fisher–Yates shuffle (aka Knuth shuffle)。
以下是wiki的简要介绍:
- 记下从1到N的数字。
- 选择一个与剩余(包括)的未打击数字之间的随机数k。
- 从低端计算,删除尚未击出的第k个数字,并将其写在别处。
- 从步骤2开始重复,直到所有数字都被删除。
- 在步骤3中记下的数字序列现在是原始数字的随机排列。
醇>
你应该提到它的低效率和好处,你如何改进它,抛出几行代码并讨论你将如何以及如何测试这段代码。
答案 1 :(得分:0)
以下是一些实现。面试时我也遇到困难,但是面试后我发现解决方案很简单。
public class MusicTrackProgram {
// O(n) in-place swapping
public static List<MusicTrack> shuffle3(List<MusicTrack> input) {
Random random = new Random();
int last = input.size() - 1;
while (last >= 0) {
int randomInt = Math.abs(random.nextInt() % input.size());
// O(1)
MusicTrack randomTrack = input.get(randomInt);
MusicTrack temp = input.get(last);
// O(1)
input.set(last, randomTrack);
input.set(randomInt, temp);
--last;
}
return input;
}
// O(n) but extra field
public static List<MusicTrack> shuffle(List<MusicTrack> input) {
List<MusicTrack> result = new ArrayList<>();
Random random = new Random();
while (result.size() != input.size()) {
int randomInt = Math.abs(random.nextInt() % input.size());
// O(1)
MusicTrack randomTrack = input.get(randomInt);
if (randomTrack.isUsed) {
continue;
}
// O(1)
result.add(randomTrack);
randomTrack.isUsed = true;
}
return result;
}
// very inefficient O(n^2)
public static List<MusicTrack> shuffle2(List<MusicTrack> input) {
List<MusicTrack> result = new ArrayList<>();
Random random = new Random();
while (result.size() != input.size()) {
int randomInt = Math.abs(random.nextInt() % input.size());
// O(1)
MusicTrack randomTrack = input.get(randomInt);
// O(1)
result.add(randomTrack);
// O(n)
input.remove(randomTrack);
}
return result;
}
public static void main(String[] args) {
List<MusicTrack> musicTracks = MusicTrackFactory.generate(1000000);
List<MusicTrack> result = shuffle3(musicTracks);
result.stream().forEach(x -> System.out.println(x.getName()));
}
}
答案 2 :(得分:0)
我们可以使用链接列表和队列在mp3播放器中实现歌曲搜索 我们可以将其扩展到以下功能:
假设最初我们有6首歌曲存储为链接列表 链接列表有2个指针:开始和结束
totalSongCount = 6
随机播放歌曲: 我们将生成一个介于1到totalSongCount之间的随机数。设为4 我们将删除代表歌曲4的节点并将其保留在结束指针之后 我们将减少totalSongCount(totalSongCount-)。
当我们减小totalSongCount时,下一次将在1-5之间生成随机数,我们可以重复该过程
要添加一首新歌,只需将其添加到链接列表并使其作为指针(添加在开头) 增加totalSongCount(totalSongCount ++)
要删除歌曲,请先找到并删除它 如果不只是减小totalSongCount(totalSongCount--),也要跟踪是否在结束指针之后。
所选歌曲可以有两个选项: 在那一刻玩 添加到播放列表(单独的队列)