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

8.2 状态机|贪心|dfs_dp

 

 

lc140 单词拆分

class Solution {
unordered_set<string> set;
vector<string> ret;
string s;
int n = 0;

public:
vector<string> wordBreak(string s, vector<string>& wordDict) {
this->s = s;
n = s.size();
for (auto& w : wordDict)
set.insert(w);

        dfs(0, "");
return ret;
}

    void dfs(int pos, string path) {
if (pos == n) {
if (!path.empty() && path.back() == ' ') {
path.pop_back();
}
ret.push_back(path);
return;
}

        for (int i = pos; i < n; ++i) {
string tmp = s.substr(pos, i - pos + 1);
if (set.count(tmp)) {
string newPath = path;
if (!newPath.empty()) {
newPath += " ";
}
newPath += tmp;
dfs(i + 1, newPath);
}
}
}
};

逻辑优化

 class Solution {

public:

    vector<string> wordBreak(string s, vector<string>& wordDict) {

        unordered_map<string,vector<string> > m;

        return helper(m,wordDict,s);

    }

    vector<string> helper(unordered_map<string,vector<string> >& m,vector<string>& wordDict,string s){

        if(m.count(s)) return m[s];

        if(s.empty()) return {""};

        vector<string> res;

        for(auto word:wordDict){

            if(s.substr(0,word.size())!=word) continue;

            vector<string> tmp=helper(m,wordDict,s.substr(word.size()));

            for(auto itm:tmp){

                res.push_back(word+(itm.empty()?"":" "+itm));

            }

        }

        m[s]=res;

        return res;

    }

};

进一步,dp

i   j双指针 扫描固定切割
一个指针找到 可切割位置,就存该点为true
dp 存状态 cache,假设每一步为切割点的状态

class Solution {
public:
bool wordBreak(string s, vector<string>& wordDict) 
{
int n=s.size();
s=' '+s;//解决 下表映射
vector<bool> dp(n+1,false);
dp[0]=true; //多开一个空间 初始化

//! 这个 地方一定要初始化为true


unordered_map<string,int> hash;

        for(auto& str:wordDict)
hash[str]++;

        for(int i=1;i<=n;i++)
{
for(int j=1;j<=i;j++)
{
string tmp=s.substr(j,i-j+1);
  if(dp[j-1]==true
&& hash.count(tmp))

dp[i]=true;
}
}
//双指针 扫描固定切割
// 一个指针找到 可切割位置,就存该点为true
//dp 存状态

return dp[n];
}
};

 

 

 

lcr138

 

#include <unordered_map>
#include <string>
using namespace std;

class Solution {
public:
bool validNumber(string s) {
unordered_map<char, int> states[9] = {
{{' ',0}, {'s',1}, {'d',2}, {'.',4}},
{{'d',2}, {'.',4}},
{{'d',2}, {'.',3}, {'e',5}, {' ',8}},
{{'d',3}, {'e',5}, {' ',8}},
{{'d',3}},
{{'s',6}, {'d',7}},
{{'d',7}},
{{'d',7}, {' ',8}},
{{' ',8}}
};

        int p = 0;
for (char c : s) {
char t;
if (c >= '0' && c <= '9') t = 'd';
else if (c == '+' || c == '-') t = 's';
else if (c == 'e' || c == 'E') t = 'e';
else if (c == '.' || c == ' ') t = c;
else t = '?';

            if (states[p].find(t) == states[p].end()) return false;
p = states[p][t];
}

        return p == 2 || p == 3 || p == 7 || p == 8;
}
};
判断一个字符串是不是合法的数字(比如"123"、"-123.45"、"3.14e5"都是合法的)。

核心思路是状态机:

1. 把字符串的每个字符转换成统一的类型(比如所有数字都算'd',正负号算's')

2. 定义好"状态转移规则":比如初始状态下遇到数字就进入"数字状态",遇到符号就进入"符号状态"

3. 从初始状态开始,逐个字符检查,按照规则跳转状态

4. 最后看最终停在的状态是不是"合法结束状态"(比如数字后面、小数点后有数字、指数后有数字等状态)

就像坐公交车:

每个站(状态)只能换乘特定的车(字符类型)去下一个站

只要有一次坐错车就到不了终点,最后到了终点站才算成功。

 

 

lc2561.

hash统计diff预处理

交换上的贪心:

sort后,考虑直接交换和通过最小元素中转两种

ret += min({need1[i], need2[i], 2 * min_val});

class Solution {

public:

    long long minCost(vector<int>& basket1, vector<int>& basket2) {

        // 统计元素差异(用哈希表精准计算需要交换的元素)

        unordered_map<int, int> diff;

        for (int x : basket1) diff[x]++;

        for (int x : basket2) diff[x]--;

        

        vector<int> need1, need2;

        int min_val = INT_MAX; // 用于中转交换的最小元素

        for (auto& [k, v] : diff)

        {

            min_val = min(min_val, k); // 记录全局最小值

            if (v % 2 != 0) return -1; // 无法平衡的情况

            int cnt = abs(v) / 2;

            if (v > 0) while (cnt--) need1.push_back(k);

            else while (cnt--) need2.push_back(k);

        }

        

        // 交换逻辑:考虑直接交换和通过最小元素中转两种方式

        sort(need1.begin(), need1.end());

        sort(need2.rbegin(), need2.rend());

        

        long long ret = 0;

        for (int i = 0; i < need1.size(); i++) {

            ret += min({need1[i], need2[i], 2 * min_val});

        }

        return ret;

    }

};

 

 

lc748

int target[26] = {0};

int curr[26] = {0};

 

if (curr[i] < target[i])
valid = false;

class Solution {
public:
string shortestCompletingWord(string licensePlate, vector<string>& words) {

int target[26] = {0};
for (auto& l : licensePlate)

         {
if (isalpha(l)) {
target[tolower(l) - 'a']++; // 直接统计小写字母频次
}
}

string ret;
int minLen = INT_MAX;

for (auto& w : words) {
int curr[26] = {0};
// 统计当前单词中每个字母的出现次数
for (auto c : w) {
curr[tolower(c) - 'a']++;
}

// 检查当前单词是否包含所有必要字母且数量足够
bool valid = true;
for (int i = 0; i < 26; i++) {
if (curr[i] < target[i])

               {
valid = false;
break;
}
}

// 更新结果:优先选更短的,长度相同则选字典序小的
if (valid) {
if (w.size() < minLen) 
{
minLen = w.size();
ret = w;
}
}
}
return ret;
}
};

 

http://www.lryc.cn/news/608113.html

相关文章:

  • Linux初步认识与指令与权限
  • 机器学习——K 折交叉验证(K-Fold Cross Validation),实战案例:寻找逻辑回归最佳惩罚因子C
  • Jotai:React轻量级原子化状态管理,告别重渲染困扰
  • React ahooks——副作用类hooks之useThrottleFn
  • react 和 react native 的开发过程区别
  • Javascript面试题及详细答案150道之(016-030)
  • 【REACT18.x】使用vite创建的项目无法启动,报错TypeError: crypto.hash is not a function解决方法
  • NEXT.js 打包部署到服务器
  • OLTP,OLAP,HTAP是什么,数据库该怎么选
  • React ahooks——副作用类hooks之useThrottleEffect
  • 超平面(Hyperplane)是什么?
  • 深入 Go 底层原理(十四):timer 的实现与高性能定时器
  • 卡尔曼滤波轨迹跟踪算法与MATLAB实现
  • 关于Web前端安全防御XSS攻防的几点考虑
  • 【软考中级网络工程师】知识点之 VRRP
  • 智能学号抽取系统V5.6.4重磅发布
  • 【Docker】RK3576-Debian上使用Docker安装Ubuntu22.04+ROS2
  • 28Rsync免密传输与定时备份
  • 【学习笔记】MySQL技术内幕InnoDB存储引擎——第9章 性能调优
  • leetcode热题——组合
  • Android性能优化--16K对齐深入解析及适配指南
  • 【数据结构初阶】--排序(二)--直接选择排序,堆排序
  • AI Agent开发学习系列 - LangGraph(10): 带有循环的Looping Graph(练习解答)
  • JavaScript特殊集合WeakMap 的使用及场景介绍
  • 【昇腾推理PaddleOCR】生产级部署方式
  • 什么是AWS Region和AWS Availability Zones
  • php完整处理word中表单数据的方法
  • Word怎样转换为PDF
  • 使用AWS免费EC2自建RustDesk远程桌面连接服务
  • 【iOS】3GShare仿写