您的位置:首页 > 编程语言 > C语言/C++

LeetCode周练Contest-38代码解析(C++)

2017-07-02 09:01 447 查看

写在前面:

LeetCode这个网站相比不必多说了吧,凡是IT圈子的人应该都知道这个网站,最近开始准备找工作,当然也免不了上去刷刷题,做一做比较经典的编程题,刚好看到LeetCode有个周练,便报名参加。

进入正题:

概要: 总共4个题,一个半小时的时间安排。题目分级为,两个easy,一个medium,一个hard。

第一题 628. Maximum Product of Three Numbers

题目描述:

Given an integer array, find three numbers whose product is maximum and output the maximum product.



这道题很简单,一开始看错了,还以为是返回操作加的最大值就好,后面才发现是操作乘,仔细想想,将原来的数组排序之后,数值范围在正负范围里面,且没有重复数,那就要注意,最大值有可能为正数,负数,0,除了0的情况,返回后三个数和前两个数还有最后一个数的乘积的最大值,基本上就是整个序列能产生的最大值了;0的情况,考虑到最后一位是0,所以之前的都是负数,那么最大值就是倒数第四位到倒数第二位之间数的乘积;

代码如下:

//理解题意,最大的结果需要乘法来计算
class Solution {
public:
int maximumProduct(vector<int>& nums) {
sort(nums.begin(), nums.end());
int lens = nums.size();
//判断最后一位是否是0,如果是零的话,那就保证了之前的数全是负数(无重复数)
if(nums[lens-1] != 0){
//不是0的情况下,两种可能
int x = nums[lens-1] * nums[lens-2] * nums[lens-3];
int y = nums[0] * nums[1] * nums[lens-1];
return x>y?x:y;
}
else   return nums[lens-2] * nums[lens-3] * nums[lens-4];
}
};


第二题 630. Course Schedule III

题目描述:

There are n different online courses numbered from 1 to n. Each course has some duration(course length) t and closed on dth day. A course should be taken
continuously for t days and must be finished before or on the dth day. You will start at the 1st day.

Given n online courses represented by pairs (t,d), your task is to find the maximal number of courses that can be taken.



这道题有点新了,对我来说,初看时感觉跟01背包问题比较像,但是又感觉不太像;而且约束条件和最终要求的条件属于同种属性的特征,并不像背包那样有容量和价值两种特征,这个就是天数作为特征;

这道题借助大家的思路,可以这样想,将结束天数按增序来排序,如果相等的话,保持位置不变,稳定排序的意思;然后用一个multiset来维护可以参加的课程,每一次用一个当前时间变量结合每个课程要花多久去对比,能不能正常上完这门课(在结束时间之前上完),如果能的话放入set中,不能的话从set里面找到一个比当前课程课时还要多的课程,移除以后添加当前课程,依据在于,之前的课程如果课时比当前课程课时还要久,但是结束时间比当前课程的结束时间还要早,都能正常上完并且放入set,那当前这门课程毫无疑问也可以放入set,保证正常修读完;代码如下:


//有点类似于背包问题,但是不同的是约束条件和要求问题解需要的条件是一个属性
//背包问题的话,约束条件是空间,但是所需解确是价值总量最大,不同的属性造就了不同的解决方法
class Solution {
public:
//在类定义中使用sort的cmp函数,需要将其定义为静态成员函数
static bool cmp(vector<int>a, vector<int>b){
return a[1] < b[1];
}

int scheduleCourse(vector<vector<int>>& courses) {
//首先按课程截止时间排序,升序规则
sort(courses.begin(), courses.end(), cmp);
multiset<int> table;
int cur = 0;
for(int i=0;i<(int)courses.size();i++){
//如果当前课程加上当前时刻不大于课程截止时间,那就计算进去
if(cur+courses[i][0] <= courses[i][1]){
table.insert(courses[i][0]);
cur += courses[i][0];
}
//如果上述条件不满足,那就考虑从之前记录的课程中,选择一个
//所花费时间比当前时间还要长的课程,删除掉它,以保证最终选
//择的课程数量最多
else if(*table.rbegin() > courses[i][0]){
cur += courses[i][0] - (*table.rbegin());
//erase方法并不能接受reverse_iterator
table.erase(--table.end());
table.insert(courses[i][0]);
}
}
return table.size();
}
};


第三题 629. K Inverse Pairs Array

题目描述:

Given two integers n and k, find how many different arrays consist of numbers from 1 to n such that there are exactly k inverse pairs.

We define an inverse pair as following: For ith and jth element in the array, if i < j and a[i] > a[j] then it's an inverse pair; Otherwise, it's not.

Since the answer may very large, the answer should be modulo 109 + 7.



难度比较高的一题,对于这种题目一开始就说,我们的结果会特别大,所以需要取模的题目,就会感觉有点虚;

这道题是求逆序对数目,不同的是,它让你求的是1~n这n个数,所有排列中的逆序对为k的排序方法有几种,这就有点无从下手了;以前遇到过只用求一个给定排列的序列的逆序对,用归并排序的思路解决即可。这道题后面看解析,使用的是动态规划的思路,用一个二维的dp数组来完成,大概先说一下思路,然后给个传送门,免得我思路不严谨误导其他人;

假设一堆序列1~n-1的排序为 x x ··· x,那么将n放在倒数第二位,逆序在原来的基础上加1,放在倒数第三,在原来的基础上加2,所以每一个dp
[k]都是跟上一层n-1的dp相关,关系为累加,如果就很直白的累加,有可能时间会用得很多,一个优化的方法就是改进dp每一个点表示在n层,逆序对小于k的值得累加结果;大概就是这个意思,传送门点击这儿


代码如下:

//解题思路
//https://discuss.leetcode.com/topic/93721/python-straightforward-with-explanation
class Solution {
private:
int MOD = 1000000007;
public:
int kInversePairs(int n, int k) {
//空间压缩+节省时间 的做法
//注意long long 和 int 型的区别
vector<vector<long long>> dp(2, vector<long long>(k+2, 1));
dp[0][0] = 0; dp[1][0] = 0;
long long old = 0;
for(int i=2;i<=n;i++){
long long cur = (old==0)?1:0;
for(int j=0;j<k+1;j++){
long long tmp = dp[old][j+1];
tmp -= j>=i?dp[old][j-i+1]:0;
dp[c
4000
ur][j+1] = (dp[cur][j] + tmp) % MOD;
}
old = cur;
}
return (dp[old][k+1] - dp[old][k] + MOD) % MOD;
}
/*int kInversePairs(int n, int k) {
vector<long long> old(k+2, 1);
old[0] = 0;
for(int i=2;i<n+1;i++){
vector<long long> cur;
cur.push_back(0);
for(int j=0;j<k+1;j++){
long long tmp = old[j+1];
tmp -= j>=i?old[j-i+1]:0;
cur.push_back((cur.back()+tmp)%MOD);
}
old = cur;
}
//return (old[k+1] - old[k]) % MOD;
return (old[k+1]-old[k]+MOD)%MOD;
}*/
};


第四题 631. Design Excel Sum Formula

题目描述:

Your task is to design the basic function of Excel and implement the function of sum formula. Specifically, you need to implement the following functions:

Excel(int H, char W): This is the constructor. The inputs represents the height and width of the Excel form. H is a positive integer, range from 1 to 26. It represents the height. W is a character range from 'A' to 'Z'. It represents that the width is the number
of characters from 'A' to W. The Excel form content is represented by a height * width 2D integer array C, it should be initialized to zero. You should assume that the first row of C starts from 1, and the first column of C starts from 'A'.

void Set(int row, char column, int val): Change the value at C(row, column) to be val.

int Get(int row, char column): Return the value at C(row, column).

int Sum(int row, char column, List of Strings : numbers): This function calculate and set the value at C(row, column), where the value should be the sum of cells represented by numbers. This function return the sum result at C(row, column). This sum formula
should exist until this cell is overlapped by another value or another sum formula.

numbers is a list of strings that each string represent a cell or a range of cells. If the string represent a single cell, then it has the following format : ColRow. For example, "F7" represents the cell at (7, F).

If the string represent a range of cells, then it has the following format : ColRow1:ColRow2. The range will always be a rectangle, and ColRow1 represent the position of the top-left cell, and ColRow2 represents the position of the bottom-right cell.



LeetCode上的特色题目,设计一个类,模仿Excel软件的功能;

取值就不多做介绍,主要讨论设置值和累加值,先说累加值,需要将选中区域(可以是重复选中很多次)的值累加之后赋值给选中的单元格,这里要注意,该单元格和选中的区域绑定;一旦选中区域中的单元格值发生了改变,那上一次和这个单元格累加相关的单元格的值也需要改变,具体可以看上述示例;

需要注意的是,一旦一个单元格被选中赋值以后,和它相绑定的关系都会失效,别的单元格改变不会再影响它的值,但是他的改变依然会影响和它相关,受它影响的单元格的值;代码如下:


/**
* Your Excel object will be instantiated and called as such:
* Excel obj = new Excel(H, W);
* obj.set(r,c,v);
* int param_2 = obj.get(r,c);
* int param_3 = obj.sum(r,c,strs);
*/

class Excel {
public:
Excel(int H, char W) {
// initialization. Because r starts from 1, I used H+1 instead of H.
Exl = vector<vector<int>> (H+1, vector<int>(W-'A'+1, 0));
fward.clear();
bward.clear();
}

void set(int r, char c, int v) {
int col = c-'A', key = r*26+col;
// update its value and all the sum related
update(r, col, v);
// This is a reset, so break all the forward links if existing
if (bward.count(key)) {
for (int k:bward[key]) {
fward[k].erase(key);
}
bward[key].clear();
}
}
// update a cell and all the sum related, using BFS
// weights are used to improve efficiency for overlapping ranges
void update(int r, int col, int v) {
int prev = Exl[r][col];
Exl[r][col] = v;
// myq is keys for cells in next level, and update is the increment for each cell
queue<int> myq, update;
myq.push(r*26+col);
update.push(v-prev);
while (!myq.empty()) {
int key = myq.front(), dif = update.front();
myq.pop();
update.pop();
if (fward.count(key)) {
for (auto it = fward[key].begin(); it != fward[key].end(); it++) {
int k = it->first;
myq.push(k);
update.push(dif*(it->second));
Exl[k/26][k%26] += dif*(it->second);
}
}
}
}

int get(int r, char c) {
return Exl[r][c-'A'];
}

int sum(int r, char c, vector<string> strs) {
// this is another reset, so break all the forward links
int col = c-'A', key = r*26+col, ans = 0;
if (bward.count(key)) {
for (int k:bward[key]) {
fward[k].erase(key);
}
bward[key].clear();
}
// get the sum over multiple ranges
for (string str:strs) {
int p = str.find(':'), left, right, top, bot;
left = str[0]-'A';
right = str[p+1]-'A';
if (p == -1)
top = stoi(str.substr(1));
else
top = stoi(str.substr(1, p-1));
bot = stoi(str.substr(p+2));
for (int i = top; i <= bot; ++i) {
for (int j = left; j <= right; ++j) {
ans += Exl[i][j];
fward[i*26+j][key]++;
bward[key].insert(i*26+j);
}
}
}
// update this cell and all the sum related
update(r, col, ans);
return ans;
}
private:
// The key of a cell is defined as 26*row+col, which is int;
// fward links a cell to all the cells which use it for sum, and it may be used for
// multiple times due to overlap ranges, so another map is used for its weight
// bward links a cell to all the cells that contribute to its sum. When reset its value,
// or reassign a new sum range to it, we need disconnect the forward link of those cells to it.
unordered_map<int, unordered_map<int, int>> fward;
unordered_map<int, unordered_set<int>> bward;
vector<vector<int>> Exl;
};


总结:

找工作路漫漫,但求不忘初心,回首对得起走过的路。

代码地址:[luuuyi/leetcode-contest]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  算法 C++