算法提升(6):01背包变种、有序表应用、int溢出边界讨论
题目1
牛牛准备参加学校组织的春游,出发前牛牛准备往背包里装入一些零食,牛牛的背包容量为w。牛牛家里一共有n袋零食,第i袋零食体积为v[i]。牛牛想知道在总体积不超过背包容量的情况下,他一共有多少种零食放法(总体积为0也算一种放法)。
思路
从左到右的尝试模型,拿或者不拿,当越界时拿的零食重量小于等于w就返回1。
//递归
int process(vector<int> v, int index, int rest);
int ways1(vector<int> v, int w)
{
if (v.size() == 0 || w < 0)
{
return 0;
}
return process(v, 0, w);
}
int process(vector<int> v, int index, int rest)
{
if (index == v.size())
{
return rest >= 0 ? 1 : 0;
}
return process(v, index + 1, rest - v[index]) + process(v, index + 1, rest);
}
//动态规划
int ways2(vector<int> v, int w)
{
if (v.size() == 0 || w < 0)
{
return 0;
}
vector<vector<int>> dp(v.size() + 1, vector<int>(w + 1));
for (int i = 0; i < dp[0].size(); i++)
{
dp[v.size()][i] = 1;
}
for (int i = v.size() - 1; i >= 0; i--)
{
for (int j = 0; j <= w; j++)
{
dp[i][j] = dp[i + 1][j - v[i]] + dp[i + 1][j];
}
}
return dp[0][w];
}
题目2
为了找到自己满意的工作,牛牛收集了每种工作的难度和报酬。牛牛选工作的标准是在难度不超过自身能力值的情况下,牛牛选择报酬最高的工作。在牛牛选定了自己的工作后,牛牛的小伙伴们来找牛牛帮忙选工作,牛牛依然使用自己的标准来帮助小伙伴们。牛牛的小伙伴太多了,于是他只好把这个任务交给了你。
class Job
{
public:
Job(int money, int hard)
{
this->money = money;
this->hard = hard;
}
public:
int money;// 该工作的报酬
int hard; //该工作的难度
};
给定一个Job类型的数组jobArr,表示所有的工作。给定一个int类型的数组arr,表示所有小伙伴的能力,每种工作不限人数,每人只能选一个工作。返回int类型的数组,表示每一个小伙伴按照牛牛的标准选工作后所能获得的报酬。
思路
先把jobArr按照hard从小到大排序,hard一样的就按照money从大到小排,排完序后hard一样的只保留money最多的,其他全部删掉,之后只剩下hard不同的,此时再删掉hard大但是money 比前面hard小的money 少 的job。然后遍历arr数组,选能力范围内hard最大的即可。
class Job
{
public:
Job(int hard, int money)
{
this->money = money;
this->hard = hard;
}
public:
int money;// 该工作的报酬
int hard; //该工作的难度
};
class JobCompare //job按照能力从小到大,能力相同的money从大到小排的规则排序
{
public:
bool operator()(const Job &j1, const Job &j2)
{
if (j1.hard == j2.hard)
{
return j1.money > j2.money;
}
else
{
return j1.hard < j2.hard;
}
}
};
vector<int> mostMoney(vector<Job> jobArr, vector<int> arr)
{
if (jobArr.size() < 1 || arr.size() < 1)
{
return {};
}
sort(jobArr.begin(), jobArr.end(), JobCompare()); //按照规则排序
map<int, int> jobMap;
jobMap.insert(make_pair(jobArr[0].hard, jobArr[0].money));
Job preJob = jobArr[0];
for (int i = 1; i < jobArr.size(); i++)
{
if (preJob.hard != jobArr[i].hard && preJob.money < jobArr[i].money) //hard一样的只保留money最多的,hard更大只保留money也更多的
{
jobMap.insert(make_pair(jobArr[i].hard, jobArr[i].money));
preJob = jobArr[i];
}
}
vector<int> ans(arr.size());
for (int i = 0; i < arr.size(); i++)
{
auto it = jobMap.lower_bound(arr[i]);
if (it == jobMap.begin() && it->first > arr[i]) //当前能力比所有工作的要求的能力都低
{
ans[i] = 0;
}
else if (it == jobMap.end()) //当前能力比所有工作要求的能力都高
{
ans[i] = jobMap.crbegin()->second;
}
else if (it->first == arr[i]) //当前能力找到了要求能力与其相同的工作
{
ans[i] = it->second;
}
else //当前能力有工作可以做,找到了第一个要求能力大于它的工作,再往前一位就是能力要求比它小的工作
{
ans[i] = (--it)->second;
}
}
return ans;
}
题目3
给定一个字符串,如果该字符串符合人们日常书写一个整数的形式,返回int类型的这个数;如果不符合或者越界返回-1或者报错。
思路
符合人们日常书写一个整数的形式有以下几条要求:
- 只有第一位允许是符号且为'-',如果第一位是'-',那么第二位不能是0
- 如果第一位是0,那么后面不能有数字
当满足上面的条件后,就可以转成整数,但是要求int类型,所以在转的过程中讨论溢出情况,具体看下面代码
bool isValid(string str);
int strToInt(string str)
{
if (!isValid(str))
{
return -1;
}
int limit1 = INT_MIN / 10;
int limit2 = INT_MIN % 10; //两个防止溢出的限制
bool isNeg = str[0] == '-' ? true : false; //判断现在要转换的数字是正数还是负数。
int ans = 0;
for (int i = isNeg ? 1 : 0; i < str.size(); i++) //负数下标为1的位置开始
{
int cur = '0' - str[i]; //不管现在转化的是正数还是负数,统一用负数转,因为INT_MIN的绝对值范围比INT_MAX的范围大1,如果要转换的数是INT_MIN,用正数转会溢出
if (ans < limit1 || (ans == limit1 && cur < limit2)) //判断要转的数是否将要溢出。
{ //如果第一种情况中了,那么ans再乘以10就溢出,所以返回-1(注意ans是负数,所以是小于号,第二种情况同理)
return -1; //如果第二种情况中了,那么ans加上cur就溢出,所以返回-1
}
ans = ans * 10 + cur;
}
if (!isNeg && ans == INT_MIN) //如果要转换的正数,但是转换结果是INT_MIN,则证明溢出
{
return -1;
}
return isNeg ? ans : -ans;
}
bool isValid(string str) //讨论是否是合格的整数形式
{
if (str.size() < 1)
{
return false;
}
if (str.size() == 1)
{
//只有一位,判断是否是0 ~ 9之间的数字
return (str[0] >= '0' && str[0] <= '9');
}
if (str[0] == '-')
{
//第一位是符号'-'
if (str[1] <= '0' || str[1] > '9')
{
//第一位是符号'-',所以要求第二位不能是0或者符号
return false;
}
for (int i = 2; i < str.size(); i++)
{
//从第三位开始判断是否是0 ~ 9之间的数字
if (str[i] < '0' || str[i] > '9')
{
return false;
}
}
}
else if(str[0] <= '0' || str[0] > '9')
{
//第一位是非'-'的符号或第一位是0
return false;
}
else
{
//第一位是数字,从第二位开始判断是否是0 ~ 9之间的数字
for (int i = 1; i < str.size(); i++)
{
if (str[i] < '0' && str[i] > '9')
{
return false;
}
}
}
return true;
}
浙公网安备 33010602011771号