booljudge(vector<int>& a, int idx, int k){ int m = a[idx]; // judge left int i = idx-2, tk = 1; while (i >= 0) { if (a[i] > m) { i--; } else { tk++; i -= 2; } } // judge right i = idx+2; while (i < a.size()) { if (a[i] > m) { i++; } else { tk++; i += 2; } }
return tk >= k; }
intminCapability(vector<int>& nums, int k){ map<int, vector<int>> m; for (int i = 0; i < nums.size(); i++) { int &x = nums[i]; if (m.find(x) != m.end()) { m[x].emplace_back(i); } else { m[x] = {i}; } }
vector<int> search_arr; for (auto &x: m) { search_arr.emplace_back(x.first); }
sort(search_arr.begin(), search_arr.end()); // bin search int l = 0, r = search_arr.size()-1; while (l < r) { int mid = (l + r) / 2; bool valid = 0; for (auto &idx: m[search_arr[mid]]) { if (judge(nums, idx, k)) { valid = 1; break; } }
booljudge(vector<int>& a, int idx, int k){ // 为方便主函数调用,不修改主函数结构,这里参数还用 idx int num = a[idx], i = 0, times = 0; while (i < a.size()) { if (a[i] <= num) { i += 2; times++; } else { i++; } } return times >= k; }
其实改完这段就可以 AC 了。但是主函数还用诸多繁杂的地方,离优雅二字有如天堑。原先代码中,我将相同的数字整合到一起,并排序,然后用哈希表记录同一个数字的不同索引位置,实际上是担心不同位置的同样的数字有不一样的结果。但是实际上这是由不正确的 judge 的思路造成的。
在修改了 judge 函数之后,这些操作就没有太多意义了。首先是相同数字不必考虑其位置,因为 judge 函数是从数组开头开始判断的。其次罗列各个出现的数值也意义不大,因为 judge 函数并不要求该数值真的在数组中出现过(当然要把参数从 index 换成具体数值),而且最终二分停止的时候,得到的结果一定在数组中出现(因为二分判断有效总是依赖于原数组)。
因此只需要找到最大值即可开始二分。修改如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
booljudge(vector<int>& a, int num, int k); // 这里改了参数,具体内容略
intminCapability(vector<int>& nums, int k){ int l = 0, r = *max_element(nums.begin(), nums.end()); // binary search while (l < r - 1) { int mid = (l + (longlong)r) / 2; // 考虑 l, r 范围,避免溢出 if (judge(nums, mid, k)) { r = mid; } else { l = mid; } } return r; }