它在 O(n) 中的原因是你必须找到两个特定的字符。一般来说,如果一个算法依赖于你从 n 个事物的列表中找到一个特定的事物,那么该算法将在 O(n) 中,但在最好的情况下将是恒定的时间。为了帮助可视化它,让我们在几个字符串上跟踪算法。
最坏情况
考虑在给定字符串的情况下找到下一个排列
a = 6 7 5 4 3 2 1
我们必须首先找到小于其后字符的最右边的字符。为此,我们可以向后搜索字符串:
6 7 5 4 3 2 1
6 7 5 4 3 2 1
6 7 5 4 3 2 1
6 7 5 4 3 2 1
6 7 5 4 3 2 1
6 7 5 4 3 2 1 找到了!
进行了 6 次比较。让我们称左索引 k,给我们 k=0。现在你必须找到大于 k 的最右边的字符。我们可以通过向后查看列表来再次做到这一点。
6 7 5 4 3 2 1
6 7 5 4 3 2 1
6 7 5 4 3 2 1
6 7 5 4 3 2 1
6 7 5 4 3 2 1
6 7 5 4 3 2 1 找到了!
进行了 6 次比较。让我们称这个索引为 l,给我们 k=0 和 l=1。现在,交换两个值。
6 7 5 4 3 2 1 --> 7 6 5 4 3 2 1
现在反转从 k+1 到列表末尾的序列。我不打算把它写出来,因为我认为理解算法并不是特别重要,但并不是说这不是一个恒定时间的操作。如果您使用的是数组,则反转元素将是线性的。这不会改变效率等级。
7 6 5 4 3 2 1 --> 7 1 2 3 4 5 6
你有下一个排列!我认为不难看出这是最坏的情况。这需要 6 + 6 = 12 次比较,等于 2 * (length(a) - 1)。如果我们扩展它,我们得到 2 * length(a) - 2。两个 2 都可以删除,因为我们不关心 big-O 中的常量加法或乘法,我们剩下长度(a),将算法放入在)。
最佳情况
现在让我们看看(短得多的)最佳情况。
a = 1 2 3 4 5 6 7
找k
1 2 3 4 5 6 7找到了!
找我
1 2 3 4 5 6 7找到了!
交换 k 和 l
1 2 3 4 5 6 7 --> 1 2 3 4 5 7 6
把k后面的所有字符都倒过来
1 2 3 4 5 7 6 --> 1 2 3 4 5 7 6
在这种情况下,我们只需要进行一次比较即可找到 k,并进行一次比较即可找到 l。在 k 之后反转元素也是一个常数时间操作,因为只有一个元素需要反转。无论字符串是 7 个字符长还是 100,000,000 个字符长,这都是正确的。找到这种排列与字符串的长度无关,最好的情况是 O(1)。