##二叉树往下搜索
###[二叉搜索树最近公共祖先](https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-search-tree)
利用二叉搜索树特性,不断靠近的去找
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
因为是二叉搜索树,则可以根据值选择哪边,在中间的为本节点,大了或小了就选边,然后遍历下去
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q)
{
while(root)
{
if (root == nullptr || root == p|| root == q)
{
break;
}
if (max(p->val,q->val) < root->val)
{
root = root->left;//向左
}
else if (min(p->val,q->val) > root->val)
{
root = root->right;//向右
}
else break;//从上而下找到的中间,就是最近公共祖先
}
return root;
}
};
##数组从后往前遍历
###[H指数](https://leetcode-cn.com/problems/h-index)
给定一位研究者论文被引用次数的数组(被引用次数是非负整数)。编写一个方法,计算出研究者的 h 指数。
h 指数的定义:h 代表“高引用次数”(high citations),一名科研人员的 h 指数是指他(她)的 (N 篇论文中)总共有 h 篇论文分别被引用了至少 h 次。且其余的 N - h 篇论文每篇被引用次数 不超过 h 次。
例如:某人的 h 指数是 20,这表示他已发表的论文中,每篇被引用了至少 20 次的论文总共有 20 篇。
示例:
输入:citations = [3,0,6,1,5]
输出:3
解释:给定数组表示研究者总共有 5 篇论文,每篇论文相应的被引用了 3, 0, 6, 1, 5 次。
由于研究者有 3 篇论文每篇 至少 被引用了 3 次,其余两篇论文每篇被引用 不多于 3 次,所以她的 h 指数是 3。
提示:如果 h 有多种可能的值,h 指数是其中最大的那个。
坐标和数值的关系,利用了有序性
技巧1是数组成员的值和数组成员的index之间的比较计算关系
int hIndex(vector<int>& citations)
{
if (citations.size() == 0)return 0;
sort(citations.begin(),citations.end());
int h(0);
for(int i = citations.size() -1;i >= 0;i--)
{
if (citations.size() - i <= citations[i])//从后往前贪心的计算
{
++h;
}
else break;
}
return h;
}
##数组双遍历
###[至少有K个重复字符的最长子串](https://leetcode-cn.com/problems/longest-substring-with-at-least-k-repeating-characters)
给你一个字符串 s 和一个整数 k ,请你找出 s 中的最长子串, 要求该子串中的每一字符出现次数都不少于 k 。返回这一子串的长度。
示例 1:
输入:s = "aaabb", k = 3
输出:3
解释:最长子串为 "aaa" ,其中 'a' 重复了 3 次。
示例 2:
输入:s = "ababbc", k = 2
输出:5
解释:最长子串为 "ababb" ,其中 'a' 重复了 2 次, 'b' 重复了 3 次。
提示:
1 <= s.length <= 104
s 仅由小写英文字母组成
1 <= k <= 105
双重遍历
class Solution {
public:
int longestSubstring(string s, int k)
{
int res = 0;
for (int i = 0;i + k <= s.size();) {
int m[26] = {0}, mask = 0, index = i;//mask标志所有字符
for (int j = i; j < s.size(); ++j) {//后面的都要计算
int t = s[j] - 'a';
++m[t];
if (m[t] < k) //当前字母合不合要求(对应位置1)
{
mask |= (1 << t);//26个字母,32位可装进去
}
else
{
mask &= (~(1 << t));
}
if (mask == 0) {//合要求的,就记录
res = max(res, j - i + 1);
index = j;
}
}
i = index + 1;//已经合要求的,跳过,从下一个(未符合的位置)开始,因为该位置跟之前的子串都不能符合要求
}
return res;
}
};
##数组从两边往中间收拢
###[盛最多水的容器](https://leetcode-cn.com/problems/container-with-most-water)
给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。
找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
返回容器可以储存的最大水量。
说明:你不能倾斜容器。
示例 1:
输入:[1,8,6,2,5,4,8,3,7]
输出:49
解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。
示例 2:
输入:height = [1,1]
输出:1
提示:
n == height.length
2 <= n <= 105
0 <= height[i] <= 104
class Solution {
public:
int maxArea(vector<int>& height) {
int left(0), right(height.size()-1);
int res = 0;
while(left < right){
res = max(res, min(height[left], height[right])*(right-left));
if(height[left] < height[right])left++;
else right--;
}
return res;
}
};
###[最接近的三数之和](https://leetcode-cn.com/problems/3sum-closest)
int threeSumClosest(vector<int>& nums, int target)
{
if (nums.size() < 3)return 0;
sort(nums.begin(),nums.end());
int res(0),diff(INT_MAX);
for(int i = 0;i < nums.size()-2;++i)
{
int left = i + 1,right = nums.size()-1;
while(left < right)//贪心遍历
{
int s = nums[i] + nums[left] + nums[right];
if (s == target)return s;
int d = abs(target - s);
if (d < diff)
{
res = s;
diff = d;
}
if (s < target)++left;
else --right;
}
}
return res;
}
搜索过程的适度优化
int threeSumClosest(vector<int>& nums, int target)
{
if (nums.size() < 3)return 0;
sort(nums.begin(),nums.end());
int res(0),diff(INT_MAX);
for(int i = 0;i < nums.size()-2;++i)
{
int left = i + 1,right = nums.size()-1;
while(left < right)
{
int s = nums[i] + nums[left] + nums[right];
if (s == target)return s;
int d = abs(target - s);
if (d < diff)
{
res = s;
diff = d;
}
if (s < target)
{
++left;
while (left < right && nums[left] == nums[left - 1])++left;
}
else
{
--right;
while (left < right && nums[right] == nums[right + 1])--right;
}
}
}
return res;
}
###[搜索二维矩阵 II](https://leetcode-cn.com/problems/search-a-2d-matrix-ii/)
编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性:
每行的元素从左到右升序排列。
每列的元素从上到下升序排列。
贪心
二维矩阵从左下角开始,往上或者往右搜索
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
if (matrix.size() == 0 || matrix[0].size() == 0)return false;
int m = matrix.size(),n = matrix[0].size();
int x = m - 1, y = 0;//左下角开始
for(;x >= 0 && y < n;)
{
if (matrix[x][y] < target)//贪心
{
++y;
}
else if (matrix[x][y] > target)
{
--x;
}
else return true;
}
return false;
}
};
###[最短无序连续子数组](https://leetcode-cn.com/problems/shortest-unsorted-continuous-subarray)
给你一个整数数组 nums ,你需要找出一个 连续子数组 ,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序。
请你找出符合题意的 最短 子数组,并输出它的长度。
示例 1:
输入:nums = [2,6,4,8,10,9,15]
输出:5
解释:你只需要对 [6, 4, 8, 10, 9] 进行升序排序,那么整个表都会变为升序排序。
示例 2:
输入:nums = [1,2,3,4]
输出:0
示例 3:
输入:nums = [1]
输出:0
提示:
1 <= nums.length <= 104
-105 <= nums[i] <= 105
class Solution {
public:
int findUnsortedSubarray(vector<int>& nums) {
if (nums.size() == 0)return 0;
int left = 0,right = -1;
for (int i = 0,maxNum = nums[i];i < nums.size();++i) {//从左往右,计算right
if (nums[i] >= maxNum) {//nums[i] < max(nums[i]) 左边,right记录位置
maxNum = nums[i];
} else {
right = i;//变小标记
}
}
for (int i = nums.size()-1,minNum = nums[i];i >= 0;--i) {//从右往左,计算left
if (nums[i] <= minNum) {//nums[i] > min(nums[i]) 右边,left记录位置
minNum = nums[i];
} else {
left = i;//变大标记
}
}
return right - left + 1;
}
};