当前位置: 首页 > news >正文

9.21 快选|倍增|栈+贡献法

 

lc2104

单调栈+贡献法 借鉴lc907

 

单调栈分别计算数组所有子数组的最大值之和与最小值之和

两者相加(因最小值通过取负转为求最大值)得到所有子数组的极差之和

lc907图解 

class Solution {

public:

    // 求nums中子数组所有最大值之和

    long long solver(vector<int>& nums)

     {

        // 考虑每个元素作为最大值出现在了多少子数组中

        // 求出nums[i]左侧严格大于他的最近元素left[i]

        // 和右侧严格大于等于它的最近元素right[i]

        // 因为nums中可能右重复元素,所以这里右侧取大于等于,

        int n = nums.size();

        vector<int> left(n, -1), right(n, n);

        stack<int> st;

        for (int i = 0; i < n; i++) {

            while (!st.empty() && nums[st.top()] <= nums[i]) {

                right[st.top()] = i; // i 恰好是栈顶元素的右边界

                st.pop();

            }

            if (!st.empty()) {

                left[i] = st.top();

            }

            st.push(i);

        }

        long long ans = 0;

        for (int i = 0; i < n; i++) {

            ans += (long long)nums[i] * (i - left[i]) * (right[i] - i);

        }

        return ans;

    }

    long long subArrayRanges(vector<int>& nums) {

        // 最大元素和最小元素的差值

        // 等价于 先求最大元素之和,在求数组元素*(-1)之后的最大元素之和(也就是之前的最小元素之和)

        long long ans = solver(nums);

        for_each(nums.begin(), nums.end(), [](int& x)

        {x = -x;});

        ans += solver(nums);

        return ans;

    }

};

 

 

lcr001

递归+倍增 实现整数除法

 

先处理正负号和边界情况(如除数为±1、结果溢出)

再通过每次将除数翻倍来快速计算商

避免直接循环相减效率低

class Solution {
public:
//利用减法实现除法 均已保证传入的a,b是负数  
unsigned int div(int a, int b)

   {
int res=0;
while(a<=b){//a的绝对值大
int temp=b;
unsigned int count=1;
while(temp>=0xc0000000&&a<=temp+temp){
count+=count;//可以减的次数翻倍
temp+=temp;//减数也翻倍
}
res+=count;
a-=temp;
}
return res;
}

    int divide(int a, int b) {
if (a == INT_MIN && b == -1) {
return INT_MAX;
}
bool positive=true;
if (a > 0) {
positive=!positive;
a = -a;
}
if (b > 0) {
positive=!positive;
b = -b;
}
unsigned int res = div(a, b);
return positive? res : -res;
}
};

 

 

 

lc1496

set<string> visited;
visited.insert("0,0");

class Solution {
public:
bool isPathCrossing(string path) {
int x = 0, y = 0;
// 使用集合存储已经走过的位置
set<string> visited;
visited.insert("0,0");


for (auto& p : path) {
if (p == 'N')
y++;
else if (p == 'S')
y--;
else if (p == 'W')
x--;
else
x++;


// 生成当前位置的字符串表示
string pos = to_string(x) + "," + to_string(y);

if (visited.count(pos))
return true;
visited.insert(pos);
}
return false;
}
};

 

lcp40.

sort+反悔贪心

 

选最大的 cnt  个数求和,若和为偶数直接返回;

若为奇数,就换前 cnt  个里最小的奇(偶)数与后面最大的偶(奇)数,取两种换法里的最大值。

 class Solution {

public:

    int maximumScore(vector<int>& cards, int cnt) {

        ranges::sort(cards, greater());

        int s = reduce(cards.begin(), cards.begin() + cnt); // 最大的 cnt 个数之和

        if (s % 2 == 0) { // s 是偶数

            return s;

        }

 

        auto replaced_sum = [&](int x) -> int {

            for (int i = cnt; i < cards.size(); i++) {

                if (cards[i] % 2 != x % 2) { // 找到一个最大的奇偶性和 x 不同的数

                    return s - x + cards[i]; // 用 cards[i] 替换 s

                }

            }

            return 0;

        };

 

        int x = cards[cnt - 1];

        int ans = replaced_sum(x); // 替换 x

        for (int i = cnt - 2; i >= 0; i--) { // 前 cnt-1 个数

            if (cards[i] % 2 != x % 2) { // 找到一个最小的奇偶性和 x 不同的数

                ans = max(ans, replaced_sum(cards[i])); // 替换

                break;

            }

        }

        return ans;

    }

};

快速选择

找数组中第k大(小)的元素,不用整体排序,更高效

class Solution {

public:

    int maximumScore(vector<int>& cards, int cnt) {

        ranges::nth_element(cards, cards.end() - cnt); // 快速选择

        int s = reduce(cards.end() - cnt, cards.end()); // 最大的 cnt 个数之和

        if (s % 2 == 0) { // s 是偶数

            return s;

        }

 

        int n = cards.size();

        // 加进来的最大偶数/奇数

        int mx[2] = {INT_MIN / 2, INT_MIN / 2}; // 除 2 防止最下面减法溢出

        for (int i = 0; i < n - cnt; i++) {

            int v = cards[i];

            mx[v % 2] = max(mx[v % 2], v);

        }

 

        // 要去掉的最小偶数/奇数

        int mn[2] = {INT_MAX / 2, INT_MAX / 2};

        for (int i = n - cnt; i < n; i++) {

            int v = cards[i];

            mn[v % 2] = min(mn[v % 2], v);

        }

 

        return max(s + max(mx[0] - mn[1], mx[1] - mn[0]), 0);

    }

};

 

http://www.dtcms.com/a/393430.html

相关文章:

  • AI.工作助手.工作提效率.AI应用开发平台
  • 【名人简历】鲁迅
  • linux文件系统基本管理
  • 2.1 进程与线程 (答案见原书 P57)
  • SDL2 开发详解
  • c++ 深拷贝之 std::string 与 char*
  • [数理逻辑] 决定性公理与勒贝格可测性(II) 一维情况
  • [Tongyi] DeepResearch Model | MODEL_PATH
  • 儿童对话玩具模型设计与实现
  • 生成器迁移的偏差消除条件
  • LeetCode 刷题【86. 分隔链表】
  • 回溯.专题
  • QML学习笔记(五)QML新手入门其三:使用Row和Colunm进行简单布局
  • 【视图功能11】视图权限控制与协作场景实践
  • YOLOv5至YOLOv12升级:交通标志识别系统的设计与实现(完整代码+界面+数据集项目)
  • 双指针算法案例:有序顺序表的交并差
  • syn和quote实现派生宏Builder
  • MQTT消息质量等级——QoS
  • 【OpenGL】shader 着色器
  • 给AI装上“眼睛”:Schema标记和技术性GEO实战部署
  • 中超-克雷桑破门 齐鲁德比泰山2-2遭海牛读秒绝平!
  • gitflow在公司的全流程
  • 如何解决 pip install 安装报错 ModuleNotFoundError: No module named ‘grpc’ 问题
  • C语言第17讲
  • 人机协同开发中的“深水炸弹”——指令上下文混淆
  • 朴素贝叶斯算法详解:原理、应用与实践
  • 强化学习的数学原理-02章 贝尔曼公式
  • C++:入门基础(2)
  • 数据架构章节考试考点及关系梳理
  • 用TRAE编程助手编写一个浏览器插件