力扣算法(2)

本文介绍了四个编程算法问题:整数反转,通过循环取数和判断来实现;出勤记录检查,通过遍历记录判断缺勤和连续迟到条件;组合生成,使用回溯法解决;元素移除,原地修改数组;以及字符串查找,提供暴力匹配和KMP算法的解决方案。这些算法展示了在不同场景下的编程思路和技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.整数反转

给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。
如果反转后整数超过 32 位的有符号整数的范围 [−231, 231 − 1] ,就返回 0。
假设环境不允许存储 64 位整数(有符号或无符号)。

示例 1:
输入:x = 123
输出:321

解题:
只要能拿到这个整数的 末尾数字 就可以了。
以12345为例,先拿到5,再拿到4,之后是3,2,1,我们按这样的顺序就可以反向拼接处一个数字了,也就能达到 反转 的效果。
加载器负责的一些主要任务如下所列:
1. 为应用程序初始化其用户模式状态比如创建初始的堆、建立起线程局部存储(TLS, thread local storage)和纤程局部存储(FLS fiber local storage)槽
2. 解析应用程序的导入表(IAT),查找所有它要求的DLL(然后递归地为每个DLL解析IAT),接着,解析DLL的导出表,确保导入的函数确实存在(特殊的前转项(forwarder entry)也可以将一个导出表项重定向到另一个DLL中)
3. 在运行时候或者根据需要加载或卸载DL,并且维护一个包含所有已被加载的模块的列表(模块数据库)
4. 使得可以支持运行时刻打补丁(称为热补丁, hotpatching)。
5. 处理清单文件( manifest file)
6. 读取任何铺垫形式的应用程序兼容性数据库,如果有必要的话,加载此铺垫(Shim)引擎DLL。
7. 启用对API集和AP重定向的支持,这是 Min Win重构工程的一个核心部分。
8. 启用基于 SwitchBranch机制的运行时刻动态兼容性缓解方案(mitigation)
在这里插入图片描述

int reverse(int x) {
        int res = 0;
        while(x!=0) {//循环取数
            //每次取末尾数字
            int tmp = x%10;
            //判断是否 大于 最大32位整数
            if (res>214748364 || (res==214748364 && tmp>7)) {
                return 0;
            }
            //判断是否 小于 最小32位整数
            if (res<-214748364 || (res==-214748364 && tmp<-8)) {
                return 0;
            }
            res = res*10 + tmp;
            x /= 10;
        }
        return res;
    }

其中有符号整数的取值范围:
byte: 8 位 -128—>127
short 16位 -32768—>32767
int 32位 -2147483648–>2147483647
long 64位 -9223372036854775808 --> 9223372036854775807

2.缺勤记录

给你一个字符串 s 表示一个学生的出勤记录,其中的每个字符用来标记当天的出勤情况(缺勤、迟到、到场)。记录中只含下面三种字符:

‘A’:Absent,缺勤
‘L’:Late,迟到
‘P’:Present,到场
如果学生能够 同时 满足下面两个条件,则可以获得出勤奖励:

按 总出勤 计,学生缺勤(‘A’)严格 少于两天。
学生 不会 存在 连续 3 天或 3 天以上的迟到(‘L’)记录。
如果学生可以获得出勤奖励,返回 true ;否则,返回 false 。

示例 1:
输入:s = “PPALLP”
输出:true
解释:学生缺勤次数少于 2 次,且不存在 3 天或以上的连续迟到记录。

解题:一次遍历
可奖励的出勤记录要求缺勤次数少于 2 和连续迟到次数少于 3。判断出勤记录是否可奖励,只需要遍历出勤记录,判断这两个条件是否同时满足即可。
遍历过程中,记录缺勤次数和连续迟到次数,根据遍历到的字符更新缺勤次数和连续迟到次数:
如果遇到‘A’,即缺勤,则将缺勤次数加 1,否则缺勤次数不变;
如果遇到‘L’,即迟到,则将连续迟到次数加 1,否则将连续迟到次数清零。
如果在更新缺勤次数和连续迟到次数之后,出现缺勤次数大于或等于 2 或者连续迟到次数大于或等于 3,则该出勤记录不满足可奖励的要求,返回 false。如果遍历结束时未出现出勤记录不满足可奖励的要求的情况,则返回 true。

//出勤记录

bool checkRecord(string s) {
	int absents = 0, lates = 0;
	for (auto ch : s) {
		if (ch == 'A') {//缺勤
			absents++;
			if (absents >= 2) {//统计
				return false;
			}
		}
		if (ch == 'L') {//迟到
			lates++;
			if (lates >= 3) {
				return false;
			}
		} else {//到场
			lates = 0;
		}
	}
	return true;
}

3.组合

给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。
你可以按 任何顺序 返回答案。

示例 1:
输入:n = 4, k = 2
输出:
[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]

标签:回溯与剪枝
dfs(cur,n) 参数表示当前位置是 cur,原序列总长度为n。原序列的每个位置在答案序列种的状态有被选中和不被选中两种,我们用temp 数组存放已经被选出的数字。在进入dfs(cur,n) 之前[1,cur−1] 位置的状态是确定的,而[cur,n] 内位置的状态是不确定的, dfs(cur,n) 需要确定 cur 位置的状态,然后求解子问题 dfs(cur+1,n)。对于 cur 位置,我们需要考虑 a[cur] 取或者不取,如果取,我们需要把 a[cur] 放入一个临时的答案数组中(即上面代码中的 temp),再执行 dfs(cur+1,n),执行结束后需要对 temp 进行回溯;如果不取,则直接执行 dfs(cur+1,n)。在整个递归调用的过程中,cur 是从小到大递增的,当 cur 增加到n+1 的时候,记录答案并终止递归。
递归结构:
1. 如果组合里有 1 ,那么需要在 [2, 3, 4] 里再找 11 个数;
2. 如果组合里有 2 ,那么需要在 [3, 4] 里再找 11数。注意:这里不能再考虑 11,因为包含 11 的组合,在第 1 种情况中已经包含。

//组合
class SolutionCombine {
public:
	vector<int> temp;
	vector<vector<int>> ans;

	void dfs(int cur, int n, int k) {
		// 剪枝:temp 长度加上区间 [cur, n] 的长度小于 k,不可能构造出长度为 k 的 temp
		if (temp.size() + (n - cur + 1) < k) {
			return;
		}
		// 记录合法的答案
		if (temp.size() == k) {
			ans.push_back(temp);
			return;
		}
		// 考虑选择当前位置
		temp.push_back(cur);
		dfs(cur + 1, n, k);
		temp.pop_back();
		// 考虑不选择当前位置
		dfs(cur + 1, n, k);
	}

	vector<vector<int>> combine(int n, int k) {
		dfs(1, n, k);
		return ans;
	}
};

调用:

SolutionCombine Combine;
	vector<vector<int>> arr;
	arr=Combine.combine(15, 3);
	for(unsigned int i = 0; i < arr.size(); ++i)
	{
		for(unsigned int j = 0;  j< arr[i].size(); ++j)
		{
		  cout<<arr[i][j]<<" ";
		}
		cout<<endl;

	}
	cout<<"一共有:"<<arr.size()<<"种"<<endl;

结果:
在这里插入图片描述

4.移除元素

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

示例 1:
输入:nums = [3,2,2,3], val = 3
输出:2, nums = [2,2]
解释:函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。你不需要考虑数组中超出新长度后面的元素。例如,函数返回的新长度为 2 ,而 nums = [2,2,3,3] 或 nums = [2,2,0,0],也会被视作正确答案。
解题:
//移除元素

int removeElement(vector<int>& nums, int val) 
{
	int n = nums.size();
	int left = 0;
	for (int right = 0; right < n; right++) //右移动
	{
		if (nums[right] != val) 
		{
			nums[left] = nums[right];
			left++;//左移动
		}
	}
	return left;//返回左的值,也就是去掉val的值之后存储的数组的容量下标
}

调用:

int arr[9] = {3,8,6,2,5,4,8,8,7};
//通过数组a的地址初始化,注意地址是从0到9(左闭右开区间)
vector<int> vec_arr(arr, arr+9);
    cout<<removeElement(vec_arr,8)<<endl;//6

5.strStr()实现

给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串出现的第一个位置(下标从 0 开始)。如果不存在,则返回 -1 。

说明:
当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。
对于本题而言,当 needle 是空字符串时我们应当返回 0 。这与 C 语言的 strstr() 以及 Java 的 indexOf() 定义相符。

示例 1:
输入:haystack = “hello”, needle = “ll”
输出:2

暴力匹配
思路及算法:我们可以让字符串 needle 与字符串haystack 的所有长度为 m的子串均匹配一次。
为了减少不必要的匹配,我们每次匹配失败即立刻停止当前子串的匹配,对下一个子串继续匹配。如果当前子串匹配成功,我们返回当前子串的开始位置即可。如果所有子串都匹配失败,则返回 -1。

//strStr()函数实现。字符匹配,子串第一次出现的下标
int strStr(string haystack, string needle) {
	if (needle.empty()) return 0;
	int m = haystack.size(), n = needle.size();
	if (m < n) return -1;
	for (int i = 0; i <= m - n; ++i) {
		int j = 0;
		for (j = 0; j < n; ++j) {
			if (haystack[i + j] != needle[j]) break;//匹配,相等就移动位置匹配下一个,不匹配就停止当前匹配对下一个位置以子串开始位置重新匹配
		}
		if (j == n) return i;
	}
	return -1;
}

对于strStr()实现还有KMP算法实现,此实现方法可以参考:https://leetcode-cn.com/problems/implement-strstr/solution/shua-chuan-lc-shuang-bai-po-su-jie-fa-km-tb86/

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/remove-element

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值