11module
22
3- def search : Unit :=
4- ()
3+ public import Std
4+ public import Init.Data.Iterators.Lemmas.Basic
5+ open Std
6+
7+ public section
8+
9+ /-! ## Implementation -/
10+
11+ def frequencies (xs : List Nat) : TreeMap Nat Nat (fun a b => compare b a) :=
12+ xs.foldl (init := ∅) (fun freq (x : Nat) => freq.alter x (fun v? => some (v?.getD 0 + 1 )))
13+
14+ def search (xs : List Nat) : Int :=
15+ let frequencies := frequencies xs
16+ let kv := frequencies.iter
17+ |>.filter (fun (k, v) => 0 < k ∧ k ≤ v)
18+ |>.map (fun (k, _) => k)
19+ |>.first?
20+ kv.getD (-1 )
21+
22+ /-! ## Tests -/
23+
24+ example : search [5 , 5 , 5 , 5 , 1 ] = 1 := by native_decide
25+ example : search [4 , 1 , 4 , 1 , 4 , 4 ] = 4 := by native_decide
26+ example : search [3 , 3 ] = -1 := by native_decide
27+ example : search [8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 ] = 8 := by native_decide
28+ example : search [2 , 3 , 3 , 2 , 2 ] = 2 := by native_decide
29+ example : search [2 , 7 , 8 , 8 , 4 , 8 , 7 , 3 , 9 , 6 , 5 , 10 , 4 , 3 , 6 , 7 , 1 , 7 , 4 , 10 , 8 , 1 ] = 1 := by native_decide
30+ example : search [3 , 2 , 8 , 2 ] = 2 := by native_decide
31+ example : search [6 , 7 , 1 , 8 , 8 , 10 , 5 , 8 , 5 , 3 , 10 ] = 1 := by native_decide
32+ example : search [8 , 8 , 3 , 6 , 5 , 6 , 4 ] = -1 := by native_decide
33+ example : search [6 , 9 , 6 , 7 , 1 , 4 , 7 , 1 , 8 , 8 , 9 , 8 , 10 , 10 , 8 , 4 , 10 , 4 , 10 , 1 , 2 , 9 , 5 , 7 , 9 ] = 1 := by native_decide
34+ example : search [1 , 9 , 10 , 1 , 3 ] = 1 := by native_decide
35+ example : search [6 , 9 , 7 , 5 , 8 , 7 , 5 , 3 , 7 , 5 , 10 , 10 , 3 , 6 , 10 , 2 , 8 , 6 , 5 , 4 , 9 , 5 , 3 , 10 ] = 5 := by native_decide
36+ example : search [1 ] = 1 := by native_decide
37+ example : search [8 , 8 , 10 , 6 , 4 , 3 , 5 , 8 , 2 , 4 , 2 , 8 , 4 , 6 , 10 , 4 , 2 , 1 , 10 , 2 , 1 , 1 , 5 ] = 4 := by native_decide
38+ example : search [2 , 10 , 4 , 8 , 2 , 10 , 5 , 1 , 2 , 9 , 5 , 5 , 6 , 3 , 8 , 6 , 4 , 10 ] = 2 := by native_decide
39+ example : search [1 , 6 , 10 , 1 , 6 , 9 , 10 , 8 , 6 , 8 , 7 , 3 ] = 1 := by native_decide
40+ example : search [9 , 2 , 4 , 1 , 5 , 1 , 5 , 2 , 5 , 7 , 7 , 7 , 3 , 10 , 1 , 5 , 4 , 2 , 8 , 4 , 1 , 9 , 10 , 7 , 10 , 2 , 8 , 10 , 9 , 4 ] = 4 := by native_decide
41+ example : search [2 , 6 , 4 , 2 , 8 , 7 , 5 , 6 , 4 , 10 , 4 , 6 , 3 , 7 , 8 , 8 , 3 , 1 , 4 , 2 , 2 , 10 , 7 ] = 4 := by native_decide
42+ example : search [9 , 8 , 6 , 10 , 2 , 6 , 10 , 2 , 7 , 8 , 10 , 3 , 8 , 2 , 6 , 2 , 3 , 1 ] = 2 := by native_decide
43+ example : search [5 , 5 , 3 , 9 , 5 , 6 , 3 , 2 , 8 , 5 , 6 , 10 , 10 , 6 , 8 , 4 , 10 , 7 , 7 , 10 , 8 ] = -1 := by native_decide
44+ example : search [10 ] = -1 := by native_decide
45+ example : search [9 , 7 , 7 , 2 , 4 , 7 , 2 , 10 , 9 , 7 , 5 , 7 , 2 ] = 2 := by native_decide
46+ example : search [5 , 4 , 10 , 2 , 1 , 1 , 10 , 3 , 6 , 1 , 8 ] = 1 := by native_decide
47+ example : search [7 , 9 , 9 , 9 , 3 , 4 , 1 , 5 , 9 , 1 , 2 , 1 , 1 , 10 , 7 , 5 , 6 , 7 , 6 , 7 , 7 , 6 ] = 1 := by native_decide
48+ example : search [3 , 10 , 10 , 9 , 2 ] = -1 := by native_decide
49+
50+ /-! ## Missing API -/
51+
52+ @ [simp, grind =]
53+ theorem Std.Iter.first?_toList {α β : Type w} [Iterator α Id β] [IteratorLoop α Id Id]
54+ [Iterators.Finite α Id] [LawfulIteratorLoop α Id Id] {it : Iter (α := α) β} :
55+ it.toList.head? = it.first? := by
56+ induction it using Iter.inductSteps with | step it ihy ihs
57+ rw [first?_eq_match_step, toList_eq_match_step]
58+ cases it.step using PlausibleIterStep.casesOn <;> simp [*]
59+
60+ theorem List.find?_eq_some_iff_of_pairwise_eq_lt {xs : List α} {cmp : α → α → Ordering}
61+ [OrientedCmp cmp] (h : xs.Pairwise (cmp · · = .lt)) :
62+ xs.find? P = some x ↔ x ∈ xs ∧ P x ∧ ∀ y ∈ xs, P y → (cmp x y).isLE := by
63+ rw [List.find?_eq_some_iff_append]
64+ constructor
65+ · intro h'
66+ refine ⟨by grind, by grind, ?_⟩
67+ intro y hm hy
68+ obtain ⟨as, bs, rfl, h''⟩ := h'.2
69+ have : y ∈ x :: bs := by grind
70+ simp only [pairwise_append, pairwise_cons] at h
71+ grind [Ordering.isLE_of_eq_eq, Ordering.isLE_of_eq_lt]
72+ · intro h'
73+ refine ⟨by grind, ?_⟩
74+ obtain ⟨as, bs, rfl⟩ := List.mem_iff_append.mp h'.1
75+ refine ⟨as, bs, rfl, ?_⟩
76+ intro a ha
77+ simp only [pairwise_append, pairwise_cons] at h
78+ replace h' := h'.2 .2
79+ specialize h' a (by grind)
80+ have : cmp x a = .gt := by
81+ rw [OrientedCmp.eq_swap (cmp := cmp), Ordering.swap_eq_gt]
82+ grind
83+ grind [Ordering.ne_gt_iff_isLE]
84+
85+ theorem List.find?_eq_find? {xs : List α} {p q : α → Bool} (h : ∀ x ∈ xs, p x = q x) :
86+ xs.find? p = xs.find? q := by
87+ ext
88+ grind [List.find?_eq_some_iff_append]
89+
90+ theorem Option.getD_map_eq_elim {o : Option α} {f : α → β} {fallback : β} :
91+ (o.map f).getD fallback = o.elim fallback f := by
92+ cases o <;> simp
93+
94+ /-! ## Verification -/
95+
96+ theorem getElem?_frequencies {k : Nat} :
97+ (frequencies xs)[k]? = (some (xs.count k)).filter (0 < ·) := by
98+ -- We express the statement in terms of `List.foldr`, which makes the induction over `xs`
99+ -- easier because the initial tree map of the fold never changes. If the statement is expressed in
100+ -- terms of `List.foldl`, we would need to generalize the statement for general initial tree maps.
101+ rw [← List.reverse_reverse (as := xs), frequencies, List.foldl_reverse]
102+ generalize xs.reverse = xs
103+ induction xs <;> grind
104+
105+ theorem mem_frequencies :
106+ x ∈ frequencies xs ↔ x ∈ xs := by
107+ rw [← TreeMap.isSome_getElem?_iff_mem, getElem?_frequencies]
108+ simp
109+
110+ theorem search_eq_getD_find? :
111+ search xs =
112+ (frequencies xs
113+ |>.toList.find? (fun x => 0 < x.1 ∧ x.1 ≤ xs.count x.1 )
114+ |>.map (↑·.fst)
115+ |>.getD (-1 : Int)) := by
116+ simp only [search, ← Iter.first?_toList, Iter.toList_map, Iter.toList_filter,
117+ TreeMap.toList_iter, List.head?_map]
118+ grind [List.find?_eq_find?, getElem?_frequencies]
119+
120+ theorem search_eq_neg_one_iff :
121+ search xs = -1 ↔ ∀ x, x = 0 ∨ xs.count x < x := by
122+ simp [search_eq_getD_find?, Option.getD_eq_iff, getElem?_frequencies]
123+ grind [List.length_filter_pos_iff]
124+
125+ theorem search_eq_iff_of_ne_neg_one (h : y ≠ -1 ) :
126+ search xs = y ↔ 0 < y ∧ y ≤ xs.count y.toNat ∧ ∀ z, 0 < z → z ≤ xs.count z → z ≤ y := by
127+ -- Prepare `OrientedCmp` instance to be used by `List.find?_eq_some_iff_of_pairwise_eq_lt`
128+ have : OrientedCmp (fun x y : Nat × Nat => compare y.1 x.1 ) := by
129+ constructor
130+ grind [Nat.compare_swap]
131+ simp only [search_eq_getD_find?, Option.getD_map_eq_elim, Option.elim]
132+ split <;> rename_i heq
133+ · simp only [List.find?_eq_some_iff_of_pairwise_eq_lt (frequencies xs).ordered_keys_toList,
134+ Prod.forall, TreeMap.mem_toList_iff_getElem?_eq_some, getElem?_frequencies] at heq
135+ grind [List.count_pos_iff, isLE_compare]
136+ · simp only [List.find?_eq_none, Prod.forall, TreeMap.mem_toList_iff_getElem?_eq_some,
137+ getElem?_frequencies, Option.filter_eq_some_iff, and_imp] at heq
138+ grind [mem_frequencies]
5139
6140/-!
7141## Prompt
@@ -10,8 +144,8 @@ def search : Unit :=
10144
11145def search(lst):
12146 '''
13- You are given a non-empty list of positive integers. Return the greatest integer that is greater than
14- zero, and has a frequency greater than or equal to the value of the integer itself.
147+ You are given a non-empty list of positive integers. Return the greatest integer that is greater than
148+ zero, and has a frequency greater than or equal to the value of the integer itself.
15149 The frequency of an integer is the number of times it appears in the list.
16150 If no such a value exist, return -1.
17151 Examples:
@@ -32,7 +166,7 @@ def search(lst):
32166 for i in range(1, len(frq)):
33167 if frq[i] >= i:
34168 ans = i
35-
169+
36170 return ans
37171```
38172
@@ -71,4 +205,4 @@ def check(candidate):
71205 assert candidate([3, 10, 10, 9, 2]) == -1
72206
73207```
74- -/
208+ -/
0 commit comments