【发布时间】:2020-06-11 09:38:09
【问题描述】:
所以我有这个问题是我从面试准备课程中购买的,我在这里也有解决方案。我知道我们正在使用二进制搜索来查找目标。该数组包含不同的单词,目标是以 a 开头的单词。我最初的方法是与 i-l 和 i +1 进行比较。如果 i - 1 大于 i 并且 i+1 小于 i 那么我们知道 i 是目标。但解决方案是做一些我不明白的事情。问题来了
我打开字典到中间的一页并开始翻阅,寻找我不知道的单词。我将每个我不知道的单词放在我在内存中创建的巨大数组中增加索引。当我到达字典的末尾时,我从头开始做同样的事情,直到到达我开始的页面。
现在我有一个单词数组,大部分都是按字母顺序排列的,除了它们从字母表中间的某个位置开始,到达末尾,然后从字母表的开头开始。换句话说,这是一个按字母顺序排列的数组,已经“旋转”过。例如:
String[] words = new String[]{
"ptolemaic",
"retrograde",
"supplant",
"undulate",
"xenoepist",
"asymptote", // <-- rotates here!
"babka",
"banoffee",
"engender",
"karpatka",
"othellolagkage",
};
写一个方法来查找“旋转点”的索引,这是我从字典的开头开始工作的地方。这个数组很大(有很多我不认识的词)所以我们要在这里高效。
解决方法如下
解决方案 这是二进制搜索的修改版本。在每次迭代中,如果我们正在查看的项目大于第一项,我们就向右走,如果我们正在查看的项目小于第一项,我们就向左走。
我们跟踪旋转点的上下界,称它们为 floorIndex 和 ceilingIndex(最初我们称它们为“地板”和“天花板”,但因为我们没有在名称中暗示类型,所以我们感到困惑并创建错误)。当 floorIndex 和 ceilingIndex 直接相邻时,我们知道 floor 是我们从字典开头开始之前添加的最后一项,而天花板是我们之后添加的第一项。
public static int findRotationPoint(String[] words) {
final String firstWord = words[0];
int floorIndex = 0;
int ceilingIndex = words.length - 1;
while (floorIndex < ceilingIndex) {
// guess a point halfway between floor and ceiling
int guessIndex = floorIndex + ((ceilingIndex - floorIndex) / 2);
// if guess comes after first word or is the first word
if (words[guessIndex].compareTo(firstWord) >= 0) {
// go right
floorIndex = guessIndex;
} else {
// go left
ceilingIndex = guessIndex;
}
// if floor and ceiling have converged
if (floorIndex + 1 == ceilingIndex) {
// between floor and ceiling is where we flipped to the beginning
// so ceiling is alphabetically first
break;
}
}
return ceilingIndex;
}
我们为什么要与 words[0] 进行比较?我们知道 words[0] 不是目标,因为它已被转移。 假设我们有 p,r,s,u,x,a,b,c,e,k,o。我们知道 a 是中间的。由于 p > a,我们将上限设置为 a。然后我们再次将 p 与 s 进行比较。所以它错过了目标。 我只是不明白这一点。请任何帮助将不胜感激
【问题讨论】:
标签: java binary-search