贪心算法-通过条件收拢范围

##二叉树往下搜索

###[二叉搜索树最近公共祖先](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;

}

};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值