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

【力扣系列题目】最后一块石头的重量 分割回文串 验证回文串 等差数列划分{最大堆 背包 动态规划}

文章目录

  • 七、最后一块石头的重量
    • 最后一块石头的重量【堆】
    • [最后一块石头的重量 II](https://leetcode.cn/problems/last-stone-weight-ii/)【背包】
  • 八、分割回文串
    • 分割回文串【分割子串方案数量】
    • [分割回文串 II](https://leetcode.cn/problems/omKAoA/)【最少分割次数】
    • [分割回文串 III](https://leetcode.cn/problems/palindrome-partitioning-iii/)【分割成k个+可修改】
    • [分割回文串 IV](https://leetcode.cn/problems/palindrome-partitioning-iv/)【是否能发成三个】
  • 九、验证回文串
    • 验证回文串
    • [验证回文串 II](https://leetcode.cn/problems/RQku0D/)【最多删除一个】
    • [验证回文串 III](https://leetcode.cn/problems/valid-palindrome-iii/)【可删除k个】
    • [验证回文串 IV](https://leetcode.cn/problems/valid-palindrome-iv/)【可删除一或两个】
  • 十、等差数列划分
    • 前言
    • 等差数列划分【等差数组的子数组个数】
    • [等差数列划分 II - 子序列](https://leetcode.cn/problems/arithmetic-slices-ii-subsequence/)
  • 十一、demo

在这里插入图片描述

七、最后一块石头的重量

最后一块石头的重量【堆】

class Solution {
public:
    int lastStoneWeight(vector<int>& stones) {
        priority_queue<int> q;
        for (int s : stones) {
            q.push(s);
        }

        while (q.size() > 1) {
            int a = q.top();
            q.pop();
            int b = q.top();
            q.pop();
            if (a > b) {
                q.push(a - b);
            }
        }
        return q.empty() ? 0 : q.top();
    }
};

最后一块石头的重量 II【背包】

class Solution {
public:
    int lastStoneWeightII(vector<int>& stones) {
        int sum = 0;
        for (auto x : stones)
            sum += x;
        int n = stones.size(), m = sum / 2;
        vector<vector<int>> dp(n + 1, vector<int>(m + 1));
        for (int i = 1; i <= n; i++) {
            for (int j = 0; j <= m; j++) {
                dp[i][j] = dp[i - 1][j];
                if (j >= stones[i - 1])
                    dp[i][j] = max(dp[i][j], dp[i - 1][j - stones[i - 1]] +
                                                 stones[i - 1]);
            }
        }

        return sum - 2 * dp[n][m];
    }
};

八、分割回文串

分割回文串【分割子串方案数量】

class Solution {
private:
    vector<vector<int>> f;
    vector<vector<string>> ans;
    vector<string> path;
    int n;

    void dfs(const string& s, int i) {
        if (i == n) {
            ans.push_back(path);
            return;
        }
        for (int j = i; j < n; ++j) {
            if (isPalindrome(s, i, j) == 1) {
                path.push_back(s.substr(i, j - i + 1));
                dfs(s, j + 1);
                path.pop_back();
            }
        }
    }

    // 0未搜索 1回文串 -1不是回文串
    int isPalindrome(const string& s, int i, int j) {
        if (f[i][j] != 0)
            return f[i][j];

        if (i > j || i == j || (i + 1 == j && s[i] == s[j]))
            return f[i][j] = 1;
        f[i][j] = (s[i] == s[j] ? isPalindrome(s, i + 1, j - 1) : -1);
        return f[i][j];
    }

public:
    vector<vector<string>> partition(string s) {
        n = s.size();
        f.assign(n, vector<int>(n));

        dfs(s, 0);
        return ans;
    }
};

分割回文串 II【最少分割次数】

class Solution
{
    void init(const string &s, vector<vector<bool>> &isPal)
    {
        int n = s.size();
        for (int i = n - 1; i >= 0; i--)
        {
            for (int j = i; j < n; j++)
            {
                if (i == j || (i + 1 == j && s[i] == s[j]))
                    isPal[i][j] = true;
                else if (s[i] == s[j])
                    isPal[i][j] = isPal[i + 1][j - 1];
            }
        }
    }

public:
    int minCut(string s)
    {
        int n = s.size();
        vector<vector<bool>> isPal(n, vector<bool>(n,false));
        init(s, isPal);

        vector<int> dp(n, INT_MAX);
        for (int i = 0; i < n; i++)
        {
            if (isPal[0][i])
                dp[i] = 0;
            else
            { 
                for (int j = 1; j <= i; j++)
                    if (isPal[j][i])
                        dp[i] = min(dp[i], dp[j - 1] + 1);
            }
        }
        return dp[n - 1];
    }
};

分割回文串 III【分割成k个+可修改】

class Solution {
    int cost2(string& s, int l, int r) {
        int ret = 0;
        for (int i = l, j = r; i < j; ++i, --j) {
            if (s[i] != s[j])
                ++ret;
        }
        return ret;
    }
    void init(string& s, vector<vector<int>>& cost) {
        int n = s.size();
        // span:区间长度; i:区间起点; j:区间终点
        for (int span = 2; span <= n; ++span) {
            for (int i = 0; i <= n - span; ++i) {
                int j = i + span - 1;
                cost[i][j] = cost[i + 1][j - 1] + (s[i] == s[j] ? 0 : 1);
            }
        }
    }

public:
    int palindromePartition(string& s, int k) {
        int n = s.size();

        vector<vector<int>> cost(n, vector<int>(n));
        init(s, cost);

        vector<vector<int>> f(n + 1, vector<int>(k + 1, INT_MAX));

        f[0][0] = 0;
        for (int i = 1; i <= n; ++i) {
            for (int j = 1; j <= min(k, i); ++j) {
                if (j == 1)
                    // f[i][j] = cost(s, 0, i - 1);
                    f[i][j] = cost[0][i - 1];
                else {
                    for (int i0 = j - 1; i0 < i; ++i0) {
                        f[i][j] =
                            // min(f[i][j], f[i0][j - 1] + cost(s, i0, i - 1));
                            min(f[i][j], f[i0][j - 1] + cost[i0][i - 1]);
                    }
                }
            }
        }

        return f[n][k];
    }
};

分割回文串 IV【是否能发成三个】

class Solution {
    void init(const string& s, vector<vector<bool>>& isPal) {
        int n = s.size();
        for (int i = n - 1; i >= 0; i--) {
            for (int j = i; j < n; j++) {
                if (i == j || (i + 1 == j && s[i] == s[j]))
                    isPal[i][j] = true;
                else if (s[i] == s[j])
                    isPal[i][j] = isPal[i + 1][j - 1];
            }
        }
    }

public:
    bool checkPartitioning(string s) {
        int n = s.size();
        vector<vector<bool>> dp(n, vector<bool>(n));
        init(s, dp);

        for (int i = 1; i < n - 1; i++)
            for (int j = i; j < n - 1; j++)
                if (dp[0][i - 1] && dp[i][j] && dp[j + 1][n - 1])
                    return true;
        return false;
    }
};

九、验证回文串

验证回文串

class Solution {
public:
    bool isPalindrome(string s) {
        int n = s.size();
        int left = 0, right = n - 1;
        while (left < right) {
            while (left < right && !isalnum(s[left]))
                ++left;

            while (left < right && !isalnum(s[right]))
                --right;

            if (left < right) {
                if (tolower(s[left]) != tolower(s[right]))
                    return false;

                ++left;
                --right;
            }
        }
        return true;
    }
};

验证回文串 II【最多删除一个】

class Solution {
public:
    bool checkPalindrome(const string& s, int low, int high) {
        int i = low, j = high;
        while (i < j) {
            if (s[i] != s[j])
                return false;
            ++i;
            --j;
        }
        return true;
    }

    bool validPalindrome(string s) {
        int low = 0, high = s.size() - 1;
        while (low < high) {
            char c1 = s[low], c2 = s[high];
            if (c1 == c2) {
                ++low;
                --high;
            } else {
                return checkPalindrome(s, low, high - 1) ||
                       checkPalindrome(s, low + 1, high);
            }
        }
        return true;
    }
};

验证回文串 III【可删除k个】

class Solution {
    bool fun(string& s, int k) {
        int n = s.size();
        vector<vector<int>> f(n, vector<int>(n));
        for (int i = n - 1; i >= 0; i--) {
            for (int j = i + 1; j < n; j++) {
                if (i == j || (i + 1 == j && s[i] == s[j]))
                    f[i][j] = 0;
                if (i + 1 == j && s[i] != s[j])
                    f[i][j] = 1;

                if (s[i] == s[j])
                    f[i][j] = f[i + 1][j - 1];
                else
                    f[i][j] = min(f[i][j - 1], f[i + 1][j]) + 1;
            }
        }

        return f[0][n - 1] <= k;
    }

public:
    vector<vector<int>> memo;
    int dfs(string& s, int i, int j) {
        if (i == j)
            return 0;

        if (i + 1 == j)
            return s[i] == s[j] ? 0 : 1;

        if (memo[i][j] != -1)
            return memo[i][j];

        if (s[i] == s[j])
            return memo[i][j] = dfs(s, i + 1, j - 1);

        return memo[i][j] = 1 + min(dfs(s, i + 1, j), dfs(s, i, j - 1));
    }
    bool isValidPalindrome(string s, int k) {
        return fun(s, k);
        
        memo.resize(s.length(), vector<int>(s.length(), -1));

        return dfs(s, 0, s.length() - 1) <= k;
    }
};

验证回文串 IV【可删除一或两个】

class Solution {
public:
    bool makePalindrome(string s) {
        int need = 0;
        int l = 0, r = s.size() - 1;

        while (l < r) {
            if (s[l] != s[r]) 
                need++;
            
            l++;
            r--;
        }

        return need <= 2;
    }
};

十、等差数列划分

前言

先看这道题

最长等差数列

按照固定i j后两位 然后找k的存在的思想在本题中无法解决。因为该题的测试用例中,a可能存在多个,题目需要“最长”, 当i前有多个a时,我们需要的是最近的a,所以初始化index数组时,不能将所有元素提前处理好,map中的键是唯一的,故,后来的a会覆盖之前的a,也就无法在枚举i时,特定的去i前找。

错误解法示例

class Solution
{
public:
    int longestArithSeqLength(vector<int> &arr)
    {
        unordered_map<int, int> indices;
        int n = arr.size();
        for (int i = 0; i < n; i++)
            indices[arr[i]] = i;

        vector<vector<int>> dp(n, vector<int>(n,2));
        int ans = 2;
        for (int i = 2; i < n; i++)
        {
            for (int j = i - 1; j >= 0; j--)
            {
                // a b c  a=b-(c-b)=2b-c
                // k j i
                int k = -1;
               
                int x = 2 * arr[j] - arr[i];
                if (indices.count(x))
                    k = indices[x];

                if (0 <= k && k < j)
                    dp[j][i] = dp[k][j] + 1;

                ans = max(ans, dp[j][i]);
            }
        }
        return ans;
    }
};

非得按照之前的思路

class Solution {
public:
    int longestArithSeqLength(vector<int>& arr) {
        int n = arr.size();
        unordered_map<int, vector<int>> hash;
        for (int i = 0; i < n; i++)
            hash[arr[i]].push_back(i);

        vector<vector<int>> dp(n, vector<int>(n, 2));
        
        int ans = 2;
        // a b c  a=b-(c-b)=2b-c
        // k j i
        for (int i = 2; i < n; i++) {
            for (int j = i - 1; j >= 0; j--) {
                int k = -1;
                int x = 2 * arr[j] - arr[i];
                if (hash.count(x)) {
                    for (int k : hash[x]) {
                        if (0 <= k && k < j)
                            dp[j][i] = dp[k][j] + 1;
                    }
                }

                ans = max(ans, dp[j][i]);
            }
        }
        return ans;
    }
};

class Solution
{
public:
    int longestArithSeqLength(vector<int> &nums)
    {
        unordered_map<int, int> hash;
        hash[nums[0]] = 0;
        int n = nums.size();
        vector<vector<int>> dp(n, vector<int>(n, 2));

        int ret = 2;
        // a b c  a=b-(c-b)=2b-c
        // k j i
        for (int j = 1; j < n; j++)
        {
            for (int i = j + 1; i < n; i++)
            {
                int a = 2 * nums[j] - nums[i];
                if (hash.count(a))
                    dp[j][i] = dp[hash[a]][j] + 1;
                ret = max(ret, dp[j][i]);
            }
            hash[nums[j]] = j;
        }
        return ret;
    }
};

等差数列划分【等差数组的子数组个数】

class Solution {
    // a b c
    // a b c d && b c d
public:
    int numberOfArithmeticSlices(vector<int>& nums) {
        // dp[i] 表⽰必须「以 i 位置的元素为结尾」的等差数列有多少种。
        int n = nums.size();
        vector<int> dp(n);
        int sum = 0;
        for (int i = 2; i < n; i++) {
            dp[i] = nums[i] - nums[i - 1] == nums[i - 1] - nums[i - 2]
                        ? dp[i - 1] + 1
                        : 0;
            sum += dp[i];
        }
        return sum;
    }
};

等差数列划分 II - 子序列

class Solution {
public:
    int numberOfArithmeticSlices(vector<int>& nums) {
        int n = nums.size();

        unordered_map<long long, vector<int>> hash;
        for (int i = 0; i < n; i++)
            hash[nums[i]].push_back(i);
        vector<vector<int>> dp(n, vector<int>(n));

        int sum = 0;
        for (int j = 2; j < n; j++)
        {
            for (int i = 1; i < j; i++) {
                long long a = (long long)nums[i] * 2 - nums[j];
                if (hash.count(a))
                    for (auto k : hash[a])
                        if (k < i)
                            dp[i][j] += dp[k][i] + 1;
                        else
                            break;
                sum += dp[i][j];
            }
        }
        return sum;
    }
};

十一、demo

最短回文串


http://www.kler.cn/a/525070.html

相关文章:

  • 全面解析文件上传下载删除漏洞:风险与应对
  • java——继承
  • YOLOv11-ultralytics-8.3.67部分代码阅读笔记-head.py
  • Ubuntu介绍、与centos的区别、基于VMware安装Ubuntu Server 22.04、配置远程连接、安装jdk+Tomcat
  • games101-作业2
  • 【Super Tilemap Editor使用详解】(十三):快捷键指南(Keyboard Shortcuts)
  • SSM总结
  • SpringBoot项目创建
  • 10.6.4 Json文件操作
  • RocketMQ原理—4.消息读写的性能优化
  • 高速PCB设计指南2——PCB设计的信号完整性
  • 【深度学习】softmax回归
  • Java—工具类类使用
  • 为什么机器学习中梯度下降是减去斜率,而不是按照其数学意义减去斜率的倒数
  • Java教程练习:学生信息管理系统
  • [STM32 - 野火] - - - 固件库学习笔记 - - -十三.高级定时器
  • 【AutoSar】汽车诊断标准协议UDS详解
  • 常见的同态加密算法收集
  • 【最后203篇系列】007 使用APS搭建本地定时任务
  • 1.27补题 回训练营
  • ODP(OBProxy)路由初探
  • 【starrocks学习】之catalog
  • java面试题:10个线程如何按顺序分别输出1-100
  • Airflow:掌握Airflow调度器基本原理
  • LangChain的开发流程
  • HTB:Active[RE-WriteUP]