Maintain a processed prefix split into values below the pivot and values at least the pivot. The remaining suffix has not yet been classified. Here The loop invariant isIn addition, the active segment remains a permutation of its original contents, and every entry outside it remains unchanged. If
a and N are the given array and its length.def partition(l: Int, r: Int, p: Int): Int = {
require(0 <= l && l <= r && r <= N)
var k = l
var j = l
while (j < r) {
if (a(j) < p) {
val t = a(k); a(k) = a(j); a(j) = t
k += 1
}
j += 1
}
k
}a(j) < p, swapping it with a(k) extends the first region; the displaced entry, when the two positions differ, already belongs in the second region. Otherwise only the second region grows. The loop variant is . At termination , soThere are exactly iterations, giving time complexity and constant auxiliary space.Take an integer pivot . There are possible values in but only occurrences of such values in the whole array. When , the pigeonhole principle givesRepeated values do not invalidate the argument: they can only reduce the number of distinct values represented by those occurrences. The other side might also contain a missing value.
There are candidate values in and exactly occurrences there. If , thenThus the pigeonhole principle givesThis conclusion does not assert that every value on the lower side is present; duplicates may leave both sides deficient.
Use missing-value search by deficient value intervals: halve the candidate value interval, and apply array partitioning only to the array segment whose entries lie in that interval.The loop invariant is , , andMore precisely, the segment contains all occurrences of original values in , and the complete array remains a permutation of its original state. The occurrences statement is essential: absence from the final segment must imply absence from the original array.
def missing(): Int = {
require(N < Int.MaxValue)
var lo = 0; var hi = N + 1
var l = 0; var r = N
while (hi - lo > 1) {
val p = lo + (hi - lo) / 2
val k = partition(l, r, p)
if (k - l < p - lo) {
hi = p; r = k
} else {
lo = p; l = k
}
}
lo
}After array partitioning, let , , , and . If , retain the left side. Otherwise the right side hasoccurrences. Either choice preserves the strict deficiency and the all-occurrences condition. The positive integer width decreases, proving termination. At width one, the active segment has fewer than one entry and is empty. ThereforeFor the time complexity, after splits the width is at most , and the scan length is smaller than that width. Summing over the levels gives a geometric series plus logarithmic overhead, hence overall, conventionally for . This proof bounds the retained occurrence count by the retained value width; it does not assume that each array partitioning splits the number of occurrences in half. The case returns zero immediately.
Articles by others on the same topic
There are currently no matching articles.