力扣069. x 的平方根
实现 int sqrt(int x) 函数。
计算并返回 x 的平方根,其中 x 是非负整数。
由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。
class Solution {
public:
int mySqrt(int x) {
//注:在中间过程计算平方的时候可能出现溢出,所以用long long。
long long i=0;
long long j=x/2+1;//对于一个非负数n,它的平方根不会大于(n/2+1)
while(i<=j)
{
long long mid=(i+j)/2;
long long res=mid*mid;
if(res==x) return mid;
else if(res<x) i=mid+1;
else j=mid-1;
}
return j;
}
};
作者:chenlele
链接:https://leetcode-cn.com/problems/sqrtx/solution/x-de-ping-fang-gen-by-gpe3dbjds1/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
求x的平方根,精确到6位小数
#include <iostream>
using namespace std;
double sqrtCount(double x, double precision) {
if (x < 0)
return -1;
double low = 1, up = x;
if (x > 0 && x < 1)
low = x, up = 1;
while (low <= up) {
double mid = low + (up - low) / 2.0;
if (abs(mid*mid - x) <= precision)
return mid;
else if (mid*mid > x)
up = mid;
else if (mid*mid < x)
low = mid;
}
return -1;
}
int main() {
double x = 11, precision = 0.000001;
double res = sqrtCount(x, precision);
cout << res << endl;
cin.get();
return 0;
}
力扣162. 寻找峰值
峰值元素是指其值大于左右相邻值的元素。
给定一个输入数组 nums,其中 nums[i] ≠ nums[i+1],找到峰值元素并返回其索引。
数组可能包含多个峰值,在这种情况下,返回任何一个峰值所在位置即可。
你可以假设 nums[-1] = nums[n] = -∞。
思路:为什么二分查找大的那一半一定会有峰值呢?(即nums[mid]<nums[mid+1]时,mid+1~N一定存在峰值) 我的理解是,首先已知 nums[mid+1]>nums[mid],那么mid+2只有两种可能,一个是大于mid+1,一个是小于mid+1,小于mid+1的情况,那么mid+1就是峰值,大于mid+1的情况,继续向右推,如果一直到数组的末尾都是大于的,那么可以肯定最后一个元素是峰值,因为nums[nums.length]=负无穷。
总结:上坡必有坡顶
int findPeakElement(vector<int>& nums) {
int left = 0, right = nums.size() - 1;
for (; left < right; ) {
int mid = left + (right - left) / 2;
if (nums[mid] > nums[mid + 1]) {
right = mid;
} else {
left = mid + 1;
}
}
return left;
}
力扣004. 寻找两个正序数组的中位数
给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。
思路:
`class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int m = nums1.size();
int n = nums2.size();
if((m + n) % 2 == 0) return (
getKthNum(nums1, nums2, (m+n)/2)
+ getKthNum(nums1, nums2, (m+n)/2 + 1)
)/ 2;
else return getKthNum(nums1, nums2, (m+n)/2 + 1);
}
double getKthNum(vector<int>& nums1, vector<int>& nums2, int k) {
int m = nums1.size();
int n = nums2.size();
int offset1 = 0;
int offset2 = 0;
while(true){
if(offset1 == m) return nums2[offset2 + k - 1];
if(offset2 == n) return nums1[offset1 + k - 1];
if(k==1) return min(nums1[offset1], nums2[offset2]);
int index1 = min(offset1 + k/2 -1, m-1);
int index2 = min(offset2 + k/2 -1, n-1);
if(nums1[index1] <= nums2[index2]){
k -= index1 - offset1 + 1;
offset1 = index1 + 1;
}
else{
k -= index2 - offset2 + 1;
offset2 = index2 + 1;
}
}
}
};
作者:ding-bin-cheng
链接:https://leetcode-cn.com/problems/median-of-two-sorted-arrays/solution/xun-zhao-liang-ge-zheng-xu-shu-zu-de-zho-nbtz/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。`
力扣1095. 山脉数组中查找目标值
给你一个 山脉数组 mountainArr,请你返回能够使得 mountainArr.get(index) 等于 target 最小 的下标 index 值。
如果不存在这样的下标 index,就请返回 -1。
何为山脉数组?如果数组 A 是一个山脉数组的话,那它满足如下条件:
首先,A.length >= 3
其次,在 0 < i < A.length - 1 条件下,存在 i 使得:
A[0] < A[1] < … A[i-1] < A[i]
A[i] > A[i+1] > … > A[A.length - 1]
你将 不能直接访问该山脉数组,必须通过 MountainArray 接口来获取数据:
MountainArray.get(k) - 会返回数组中索引为k 的元素(下标从 0 开始)
MountainArray.length() - 会返回该数组的长度
思路:
1.先二分找到峰顶
2.对左右区间二分找target
class Solution {
int n;
public:
int findInMountainArray(int target, MountainArray& mountainArr) {
n = mountainArr.length();
int top = findTop(mountainArr);
int pos1 = help1(0, top, target, mountainArr);
if (pos1 != -1) return pos1;
int pos2 = help2(top + 1, n - 1, target, mountainArr);
return pos2;
}
int findTop(MountainArray& mountainArr) {
int l = 0, r = n - 1;
while (l < r) {
int mid = (l + r) >> 1;
if (mountainArr.get(mid) < mountainArr.get(mid + 1)) l = mid + 1;
else r = mid;
}
return l;
}
int help1(int l, int r, const int& target, MountainArray& mountainArr) {
while (l <= r) {
int mid = (l + r) >> 1;
if (mountainArr.get(mid) == target) return mid;
if (mountainArr.get(mid) < target) l = mid + 1;
else r = mid - 1;
}
return -1;
}
int help2(int l, int r, const int& target, MountainArray& mountainArr) {
while (l <= r) {
int mid = (l + r) >> 1;
if (mountainArr.get(mid) == target) return mid;
if (mountainArr.get(mid) > target) l = mid + 1;
else r = mid - 1;
}
return -1;
}
};
作者:heygary
链接:https://leetcode-cn.com/problems/find-in-mountain-array/solution/c-zhong-gui-zhong-ju-de-8msjie-fa-er-fen-shi-jian-/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
力扣300. 最长递增子序列
给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。
子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。
思路:
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int n=(int)nums.size();
if (n == 0) return 0;
vector<int> dp(n, 0);
for (int i = 0; i < n; ++i) {
dp[i] = 1;
for (int j = 0; j < i; ++j) {
if (nums[j] < nums[i]) {
dp[i] = max(dp[i], dp[j] + 1);
}
}
}
return *max_element(dp.begin(), dp.end());
}
};
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/longest-increasing-subsequence/solution/zui-chang-shang-sheng-zi-xu-lie-by-leetcode-soluti/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
贪心+二分算法
#include <iostream>
#include <vector>
using namespace std;
class Solution {
public:
int lengthOfLIS(vector<int> &nums) {
int len = nums.size();
if (len < 2) {
return len;
}
vector<int> tail;
tail.push_back(nums[0]);
// tail 结尾的那个索引
int end = 0;
for (int i = 1; i < len; ++i) {
if (nums[i] > tail[end]) {
tail.push_back(nums[i]);
end++;
} else {
int left = 0;
int right = end;
while (left < right) {
int mid = (left + right) >> 1;
if (tail[mid] < nums[i]) {
left = mid + 1;
} else {
right = mid;
}
}
tail[left] = nums[i];
}
}
return end + 1;
}
};
作者:liweiwei1419
链接:https://leetcode-cn.com/problems/longest-increasing-subsequence/solution/dong-tai-gui-hua-er-fen-cha-zhao-tan-xin-suan-fa-p/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
求出字典序最小的最长递增子序列
第二步求子序列的说明:
怎么找到字典序最小的解
需要 maxLen[] 记录以 arr[i] 为结尾的最长子序列的长度。
本例 maxLen [ 1 1 2 2 3 3 4 5 4 ]
又贪: 当 maxLen[i] == maxLen[i - 1] ,最小字典序要选 arr[i] ,跳过 i - 1。 反证 :本例 maxLen[4] maxLen[5]均为3 ,对应元素 6、4 。 如果换位成 4、6,那么 maxLen[5] 的将变为 4 ,矛盾。 (即 maxLen[i] == maxLen[i - 1] 推出 arr[i] <= arr[i - 1])
为了回避掉 arr[8] 对于 end[4] 的无效更新(因为 arr[7] 是最长序列结尾)
//
// Created by jt on 2020/9/14.
//
#include <vector>
#include <algorithm>
using namespace std;
class Solution {
public:
/**
* return the longest increasing subsequence
* @param arr int整型vector the array
* @return int整型vector
*/
vector<int> LIS(vector<int>& arr) {
// write code here
// 第一步:利用贪心+二分求最长递增子序列长度
vector<int> res;
vector<int> maxLen;
if (arr.size() < 1) return res;
res.emplace_back(arr[0]); // 注:emplace_back(val)作用同push_back,效率更高
maxLen.emplace_back(1);
for (int i = 1; i < arr.size(); ++i) {
if (arr[i] > res.back()) {
res.emplace_back(arr[i]);
maxLen.emplace_back(res.size());
} else {
// lower_bound(begin, end, val)包含在<algorithm>中
// 它的作用是返回有序数组begin..end中第一个大于等于val的元素的迭代器
int pos = lower_bound(res.begin(), res.end(), arr[i]) - res.begin();
res[pos] = arr[i];
maxLen.emplace_back(pos+1);
}
}
// 第二步:填充最长递增子序列
for (int i = arr.size()-1, j = res.size(); j > 0; --i) {
if (maxLen[i] == j) {
res[--j] = arr[i];
}
}
return res;
}
};
力扣354. 俄罗斯套娃信封问题
给你一个二维整数数组 envelopes ,其中 envelopes[i] = [wi, hi] ,表示第 i 个信封的宽度和高度。
当另一个信封的宽度和高度都比这个信封大的时候,这个信封就可以放进另一个信封里,如同俄罗斯套娃一样。
请计算 最多能有多少个 信封能组成一组“俄罗斯套娃”信封(即可以把一个信封放到另一个信封里面)。
注意:不允许旋转信封。
思路:转换成最长递增子序列
在二分查找的方法中,对宽度升序,并且在宽度相同时对高度降序的目的:
1.保证迭代排序后的envelopes时,宽度是非递减的(注意:相邻的两个envelope可能宽度相同)。
2.在相邻两个envelope宽度相同的情况时,两者的高度是非递增的,比如(3, 5), (3, 3), 不会出现“相同高度,后者套前者”的情况。
class Solution {
public:
int maxEnvelopes(vector<vector<int>>& envelopes) {
if (envelopes.empty()) {
return 0;
}
int n = envelopes.size();
sort(envelopes.begin(), envelopes.end(), [](const auto& e1, const auto& e2) {
return e1[0] < e2[0] || (e1[0] == e2[0] && e1[1] > e2[1]);
});
vector<int> f = {envelopes[0][1]};
for (int i = 1; i < n; ++i) {
if (int num = envelopes[i][1]; num > f.back()) {
f.push_back(num);
}
else {
auto it = lower_bound(f.begin(), f.end(), num);
*it = num;
}
}
return f.size();
}
};
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/russian-doll-envelopes/solution/e-luo-si-tao-wa-xin-feng-wen-ti-by-leetc-wj68/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
力扣410. 分割数组的最大值
给定一个非负整数数组 nums 和一个整数 m ,你需要将这个数组分成 m 个非空的连续子数组。
设计一个算法使得这 m 个子数组各自和的最大值最小。
思路:
由题意可知:子数组的最大值是有范围的,即在区间 [max(nums),sum(nums)]之中。
令 l=max(nums),h=sum(nums),mid=(l+h)/2,计算数组和最大值不大于mid对应的子数组个数 cnt(这个是关键!)
如果 cnt>m,说明划分的子数组多了,即我们找到的 mid 偏小,故 l=mid+1;
否则,说明划分的子数组少了,即 mid 偏大(或者正好就是目标值),故 h=mid。
再理解:
我先猜一个mid值,然后遍历数组划分,使每个子数组和都最接近mid(贪心地逼近mid),这样我得到的子数组数一定最少;
如果即使这样子数组数量仍旧多于m个,那么明显说明我mid猜小了,因此 lo = mid + 1;
而如果得到的子数组数量小于等于m个,那么我可能会想,mid是不是有可能更小?值得一试。因此 hi = mid;
int splitArray(vector<int>& nums, int m) {
long l = nums[0], h = 0;//int类型在这里不合适,因为h可能会超过int类型能表示的最大值
for (auto i : nums)
{
h += i;
l = l > i ? l : i;
}
while (l<h)
{
long mid = (l + h) / 2;
long temp = 0;
int cnt = 1;//初始值必须为1
for(auto i:nums)
{
temp += i;
if(temp>mid)
{
temp = i;
++cnt;
}
}
if(cnt>m)
l = mid + 1;
else
h = mid;
}
return l;
}
作者:coder233
链接:https://leetcode-cn.com/problems/split-array-largest-sum/solution/er-fen-cha-zhao-by-coder233-2/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。