贪心 字典序最小问题

#贪心 字典序最小问题
题目大意:给你一个长为N的字符串S,并提供下列2种操作

  • 把S的第一个字母添加到字符串T的末尾,并从S中删除
  • 把S的最后一个字母添加到字符串T的末尾,并从S中删除

让你构造出字典序最小的字符串T

###思路
因为每次我们能直接考虑的只有S的首尾字母,所以每次添加到T中的不是第一个就是最后那一个,没有别的方法,并且都是添加到T的末尾

根据字典序的定义,越靠前的字母越小,则字典序越小,所以我们每次尽量先把更小的字母加到T的靠前位置,这个策略比较直观。

不过当S的首位相同时,该如何选择呢?随便选择一个?肯定不可以,这个是有反例的
比如CDBC,如果我们选择首字母,则得到的答案会是CCBD,而不是最优解CBCD

不过这个问题其实很好解决,当S的两端S[0]与S[N]相同,则我们可以假装把这两个字母忽略掉,然后剩下的S[1]到S[N-1]就形成了一个新的字串,此时我们对这个字串继续之前的策略,哪边更小我们原串就选择哪边

所以总结一下,我们可以这样说:

我们比较S和将S反转后的S’的字典序大小
1. S < S’我们选择首字母
2. S > S’我们选择尾字母

代码:

#include <iostream>
using namespace std;

char S[1005];
int N;

int main() {
	cin >> N;
	for (int i = 0; i < N; ++i) {
		cin >> S[i];
	}

	int l = 0, r = N - 1;
	while (l <= r) {
		bool lt = false;
		for (int i = 0; i <= r - l; ++i) {
			if (S[l] > S[r]) {
				break;
			} else if (S[l] < S[r]) {
				lt = true;
				break;
			}
		}
		if (lt) {
			cout << S[l++];
		}
		else {
			cout << S[r--];
		}
	}
	return 0;
}
### 字典序最小算法的实现方法 字典序是一种常见的字符串比较方式,其核心在于逐位对比字符的ASCII码值。为了找到字典序最小的结果,通常会涉及一些特定的操作,比如去重、重新排列或者删除某些字符。 #### 去重并保持字典序最小 对于给定的小写字符串`str`,目标是删除多余的重复字符,使每种字符仅保留一次,并确保结果字符串具有最小字典序[^2]。以下是具体的实现逻辑: 1. **维护访问状态**:创建一个布尔数组或集合用于记录某个字符是否已被加入结果序列。 2. **计数统计**:通过遍历输入字符串构建频率表,了解每个字符剩余的数量。 3. **贪心策略应用**:利用栈结构存储当前候选字符,在满足条件的情况下弹出较大的字符以保证整体顺序最优。 下面是基于上述原理的一种Python实现方案: ```python def removeDuplicateLetters(s): last_occurrence = {c: i for i, c in enumerate(s)} # 记录最后一次出现的位置 stack = [] seen = set() for idx, char in enumerate(s): if char in seen: continue while stack and char < stack[-1] and last_occurrence[stack[-1]] > idx: removed_char = stack.pop() seen.remove(removed_char) stack.append(char) seen.add(char) return ''.join(stack) ``` 此函数首先建立字母最后位置映射表以便后续判断能否移除某元素;接着运用循环迭代每一个待处理符号,依据既定规则调整堆叠内容直至完成全部操作流程。 #### 排列组合中的字典序生成 当面对全排列场景下的字典序需求时,则可借助回溯技术减少不必要的移动次数从而提升效率[^1]。这类问题往往围绕如何高效枚举所有可能情况展开讨论。 --- ### 示例分析 假设输入串为 `"cbacdcbc"` ,按照以上描述执行过程如下: - 初始化 `last_occurrence={'c':7,'b':6,'a':2,'d':4}` 和空列表作为栈; - 遍历时依次考虑各单元格数据关系,最终得到输出结果 `"acdb"` 符合预期设定标准即最小子序列形式呈现出来。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值