期中小结(上)
先总结几道简单题,其中涉及贪心算法、分治、BFS、动态规划、递归等思想。
1000. 分组
Description
对于一个整数数列A[0], A[1], …, A[N-1]进行分组,要求每组1到2个数,并且同组之和不能大于w. 求最少可以分成多少组.
1 <= N <= 100000, 1 <= A[i] <= w <= 1000000000.
请实现下面Solution类中计算minPartition(A, w)的函数.
class Solution {
public:
int minPartition(vector<int> A, int w) {
}
};
例1:当A = {2, 5, 4, 3}, w = 5, minPartition(A, w)返回3. 将2和3放一组,4和5各自单独作为一组,共3组.
例2:当A = {2, 5, 4, 3}, w = 7, minPartition(A, w)返回2. 将2和5放一组,3和4一组,共2组.
注意:你只需要提交Solution类的代码,你在本地可以编写main函数测试程序,但不需要提交main函数的代码. 注意不要修改类和函数的名称.
核心思想:贪心算法
思路
1.将数组排好序;
2.维护两个指针,一个从最左(最小值)开始,另一个从最右边开始(最大值);
3.将两个指针所指的元素之和(当前还未分组的最大值与最小值之和)与给定数w比较,若元素之和大于w,则right指针左移,即调整元素之和使其减小,同时将刚刚right所指元素单独划入分组(该值不会大于w),计数器+1;反之同理,left指针右移。
解题代码
class Solution {
public:
int minPartition(vector<int> A, int w) {
int n = A.size();
if (n <= 1) return 1;
sort(A.begin(), A.end());
int count = 0;
int left = 0, right = n - 1;
while(left <= right) {
if(A[left] + A[right] <= w) {
left++;
right--;
} else {
right--;
}
count++;
}
return count;
}
};
时间复杂度
O(n)
1001. 最小差
Description
对于一个整数数列A[0], A[1], …, A[N-1],要求在其中找两个数,使得它们的差的绝对值最小.
2 <= N <= 100, -1000 <= A[i] <= 1000.
请实现下面Solution类中计算minDifference(A)的函数,返回值为能得到的最小差.
class Solution {
public:
int minDifference(vector<int> A) {
}
};
例1:当A = {2, 7, -2}, 返回4.
例2:当A = {-8, 10, 30, 10}, 返回0.
注意:
1. 你只需要提交Solution类的代码,你在本地可以编写main函数测试程序,但不需要提交main函数的代码. 注意不要修改类和函数的名称.
2. 如果使用全局变量或类成员函数,请记得在minDifference中初始化,因为测试时,minDifference可能在一次程序执行中被反复调用.
核心思想:分治
思路
暴力破解
考试的时候没想那么多,直接双重循环把所有差走了一遍。感觉O(n^2)的代价也还可以接受。
分治
对数组先进行快速排序,再依次比较相邻的差
解题代码
这题代码就略了
时间复杂度
暴力破解:O(n^2)
分治:O(nlogn)
1002. 合并二叉树
Description
输入两个二叉树T1和T2,要求对T1和T2进行合并. 合并是指将二叉树同一位置节点上的数求和,作为合并后二叉树相应位置节点的数值. 如果某个位置上只有一个二叉树有节点,则合并后的二叉树对应位置上的节点上的数值就等于这个节点上的数值.
例如:
T1 T2
1 2
/ \ / \
3 2 1 3
/ \ \
5 4 7
T1 T2
合并后:
3
/ \
4 5
/ \ \
5 4 7
T1和T2的结点数均不多于100000,每个结点的数值在1和1000之间.
请为下面的Solution类实现解决上述问题的merge函数,函数的两个参数T1和T2分别代表两个二叉树的根节点,函数返回值为合并后的二叉树的根节点.
/**
Definition for a binary tree node.
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
*/
class Solution {
public:
TreeNode* merge(TreeNode* T1, TreeNode* T2) {
}
};
注意:你只需要提交Solution类的代码,你在本地可以编写main函数测试程序,但不需要提交main函数的代码,也不需要提交TreeNode的定义. 注意不要修改类和函数的名称.
核心思想:递归
思路
数据结构是树的题目大多采用递归。
找到停止条件后即可开始递归。
解题代码
class Solution {
public:
TreeNode* merge(TreeNode* T1, TreeNode* T2) {
struct TreeNode* temp = T1;
mergeRec(T1, T2);
return temp;
}
TreeNode* mergeRec(struct TreeNode* l, struct TreeNode* r) {
if (l && r) {
l->val += r->val;
l->left = mergeRec(l->left, r->left);
l->right = mergeRec(l->right, r->right);
return l;
} else {
return l ? l : r;
}
}
};
1003. 最近的0
Description
输入一个N*M的01矩阵A,对矩阵的每个位置,求至少经过多少步可以到达一个0. 每一步可以往上下左右走一格.
请为下面的Solution类实现解决这一问题的函数nearestZero,函数参数A为给出的01矩阵,A的行数和列数均不大于100. 函数的返回值是问题的答案.
class Solution {
public:
vector<vector<int>> nearestZero(vector<vector<int>>& A) {
}
};
例如:
A=
1 1 1
0 1 1
0 0 1答案为
1 2 3
0 1 2
0 0 1
注意:你只需要提交Solution类的代码,你在本地可以编写main函数测试程序,但不需要提交main函数的代码. 注意不要修改类和函数的名称.
核心思想:BFS
思路
同leetcode542. 01 Matrix
解题代码
class Solution {
public:
vector<vector<int>> updateMatrix(vector<vector<int>>& matrix) {
}
};
// 点数据结构
struct Point {
int x;
int y;
Point(int _x, int _y) : x(_x), y(_y) {}
};
// 代表四个方向
int Posx[4] = {-1, 0, 1, 0};
int Posy[4] = {0, -1, 0, 1};
class Solution {
public:
bool isValid(int x, int y, vector<vector<int>>& A) {
return x >= 0 && x < A.size() &&
y >= 0 && y < A[x].size();
}
vector<vector<int>> updateMatrix(vector<vector<int>>& A) {
queue<Point> q1, q2; // 两个保存同节点的队列
int step = 1; // 表示走到0所需的步数,遍历一个队列赋一次值
// 将1更新成-1,即未赋值,将0入队
for (int i = 0; i < A.size(); i++)
for (int j = 0; j < A[i].size(); j++)
if (A[i][j] == 0) q1.push(Point(i, j));.
else A[i][j] = -1;
while (!q1.empty() || !q2.empty()) {
while (!q1.empty()) {
Point p = q1.front();
q1.pop();
// 添加四个方向的节点
for (int i = 0; i < 4; i++) {
int newx = p.x + Posx[i];
int newy = p.y + Posy[i];
if (isValid(newx, newy, A) && A[newx][newy] == -1) {
A[newx][newy] = step;
q2.push(Point(newx, newy));
}
}
}
step++;
while (!q2.empty()) {
Point p = q2.front();
q2.pop();
// 添加四个方向的节点
for (int i = 0; i < 4; i++) {
int newx = p.x + Posx[i];
int newy = p.y + Posy[i];
if (isValid(newx, newy, A) && A[newx][newy] == -1) {
A[newx][newy] = step;
q1.push(Point(newx, newy));
}
}
}
step++;
}
return A;
}
};
时间复杂度
O(rowsNum*colsNum)
1006. 最长公共子串
Description
给定两个字符串x = x1x2…xn和y = y1y2…ym, 请找出x和y的最长公共子串的长度,也就是求出一个最大的k,使得存在下标i和j有xixi+1…xi+k-1 = yjyj+1…yj+k-1.
x和y只含有小写字母,长度均在1和1000之间.
请为下面的Solution类实现解决上述问题的函数longestSubstring,函数的参数x和y为给出的两个单词,返回值为最长公共子串的长度.
class Solution {
public:
int longestSubstring(string x, string y) {
}
};
例1:x = “abcd”, y = “cdef”,返回值为2.
例2:x = “abcabc”, y = “xyz”,返回值为0.
例3:x = “introduction”, y = “introductive”,返回值为10.
注意:
1. 你只需要提交Solution类的代码,你在本地可以编写main函数测试程序,但不需要提交main函数的代码. 注意不要修改类和函数的名称.
2. 如果使用全局变量或类成员函数,请记得在longestSubstring中初始化,因为测试时,longestSubstring可能在一次程序执行中被反复调用.
核心思想:动态规划
思路
同leetcode718. Maximum Length of Repeated Subarray
解题代码
class Solution {
public:
int longestSubstring(string x, string y) {
int row = x.length() + 1;
int col = y.length() + 1;
int v[row+1][col+1] ;
int max = 0;
for (int i = 0; i < row; i++) v[i][0] = 0;
for (int j = 0; j < col; j++) v[0][j] = 0;
for (int i = 1; i < row; i++) {
for (int j = 1; j < col; j++) {
if (x[i-1] == y[j-1]) {
v[i][j] = 1 + v[i-1][j-1];
if (v[i][j] > max) max = v[i][j];
} else {
v[i][j] = 0;
}
}
}
return max;
}
};
时间复杂度
O(n^2)