中级提升班-3
题目0返回1数量最多的行
一个矩阵,每行0在左边,1在右边,返回矩阵中1个数最多的行数
- 准备list用于存放行数,ans统计最多的1的个数,从右上角开始走,左边有1则ans++,直到没有1了往下走,并记录行数,如哦下方行为0则继续往下—如图所示
void max1(vector<vector<int>> nums) {
int i = 0;
int j = nums[0].size() - 1;
int ans = 1;
int maxRes = 0;
vector<int> res; vector<int> res1;
while (i < nums.size() && j >= 0) {
if (nums[i][j] == 1) {
while (nums[i][j] == 1 && j - 1 >= 0 && nums[i][j - 1] == 1) {
j--;
ans++;
}
if (ans > maxRes) {
maxRes = ans;
res.clear();
res.push_back(i);
i++;
}
else if (ans == maxRes) {
res.push_back(i);
i++;
}
}
else {
i++;
}
}
for (int i = 0; i < res.size(); i++) {
cout << res[i] << " ";
}
}
题目一 打包机器/洗衣机
有n个打包机器从左到右一字排开,上方有一个自动装置会抓取一批放物品到每个打
包机上,放到每个机器上的这些物品数量有多有少,由于物品数量不相同,需要工人
将每个机器上的物品进行移动从而到达物品数量相等才能打包。每个物品重量太大、
每次只能搬一个物品进行移动,为了省力,只在相邻的机器上移动。请计算在搬动最
小轮数的前提下,使每个机器上的物品数量相等。如果不能使每个机器上的物品相同,
返回-1。
例如[1,0,5]表示有3个机器,每个机器上分别有1、0、5个物品,经过这些轮后:
第一轮:1 0 <- 5 => 1 1 4
第二轮:1 <-1<- 4 => 2 1 3
第三轮:
2 1 <- 3 => 2 2 2
移动了3轮,每个机器上的物品相等,所以返回3
例如[2,2,3]表示有3个机器,每个机器上分别有2、2、3个物品,
这些物品不管怎么移动,都不能使三个机器上物品数量相等,返回-1
分成以下三类情况:
因此,从左开始遍历数组,每次计算以该点为i时,所对应的最少次数,数组中最大的数为所求值
int packingMachine(vector<int> arr) {
if (arr.size() < 1) {
return -1;
}
int sum = 0;
for (int i = 0; i < arr.size(); i++) {
sum += arr[i];
}
if (sum % arr.size() != 0) {
return -1;
}
int ave = sum / arr.size();
int leftSum = 0;
int ans = 0;
for (int i = 0; i < arr.size(); i++) {
// 左边实际-左边所需,负数代表需要输入,正数代表需要输出
int leftRest = leftSum - i * ave;
// 右边实际-右边所需,负数代表需要输入,正数代表需要输出
int rightRest = sum - leftSum - arr[i] - ave * (arr.size() - i - 1);
if (leftRest < 0 && rightRest < 0) {
ans = max(ans, abs(leftRest)+ abs(rightRest));
}
else {
ans = max(ans, max(abs(leftRest), abs(rightRest)));
}
leftSum += arr[i];// 别忘记
}
return ans;
}
题目二zigzag
矩阵题设置边界点
用zigzag的方式打印矩阵,比如如下的矩阵
0 1 2 3
4 5 6 7
8 9 10 11
打印顺序为:0 1 4 8 5 2 3 6 9 10 7 11
-
无需考虑单个情况,从整体开始考虑
-
如图,设定两个边界点,一次按照斜线打印两个边界点之间的值
自己写的代码
void zigzag(vector<vector<int>> arr) {
int x1 = 0, y1 = 0;
int x2 = 0, y2 = 0;
bool sign = true;
while (x1 != arr.size()) {
if (sign == true) {
int i = x2, j = y2;
while (j != y1 + 1) {
cout << arr[i--][j++] << " ";
}
}
else {
int i = x1, j = y1;
while (i != x2 + 1) {
cout << arr[i++][j--] << " ";
}
}
sign = !sign;
if (y1 + 1 < arr[0].size()) {
y1++;
}
else {
x1++;
}
if (x2 + 1 < arr.size()) {
x2++;
}
else {
y2++;
}
}
}
左神代码
public static void printMatrixZigZag(int[][] matrix) {
int tR = 0;
int tC = 0;
int dR = 0;
int dC = 0;
int endR = matrix.length - 1;
int endC = matrix[0].length - 1;
boolean fromUp = false;
while (tR != endR + 1) {
printLevel(matrix, tR, tC, dR, dC, fromUp);
tR = tC == endC ? tR + 1 : tR;
tC = tC == endC ? tC : tC + 1;
dC = dR == endR ? dC + 1 : dC;
dR = dR == endR ? dR : dR + 1;
fromUp = !fromUp;
}
System.out.println();
}
public static void printLevel(int[][] m, int tR, int tC, int dR, int dC,
boolean f) {
if (f) {
while (tR != dR + 1) {
System.out.print(m[tR++][tC--] + " ");
}
} else {
while (dR != tR - 1) {
System.out.print(m[dR--][dC++] + " ");
}
}
}
题目三 用螺旋方式打印矩阵
矩阵题设置边界点
用螺旋的方式打印矩阵,比如如下的矩阵
0 1 2 3
4 5 6 7
8 9 10 11
打印顺序为:0 1 2 3 7 11 10 9 8 4 5 6
- 设置对角线为两个边界点,打印以该边界点组成的矩形的边框。
- 最后会有三种特殊情况,需要讨论
void rotateMatrix(vector<vector<int>> arr) {
int x1 = 0, y1 = 0;
int x2 = arr.size() - 1, y2 = arr[0].size() - 1;
while (x1 <= x2 && y1 <= y2) {
if (x1 == x2) {
for (int j = y1; j <= y2; j++) {
cout << arr[x1][j] << " ";
}
break;
}
if (y1 == y2) {
for (int i = x1; i <= x2; i++) {
cout << arr[i][y1] << " ";
}
break;
}
for (int i = y1; i <= y2; i++) {
cout << arr[x1][i] << " ";
}
for (int j = x1 + 1; j <= x2; j++) {
cout << arr[j][y2] << " ";
}
for (int i = y2 - 1; i >= y1; i--) {
cout << arr[x2][i] << " ";
}
for (int j = x2 - 1; j > x1; j--) {
cout << arr[j][x1] << " ";
}
x1++;
y1++;
x2--;
y2--;
}
}
题目四 矩阵旋转
矩阵题设置边界点
给定一个正方形矩阵,只用有限几个变量,实现矩阵中每个位置的数顺时针转动
90度,比如如下的矩阵
0 1 2 3
4 5 6 7
8 9 10 11
12 13 14 15
矩阵应该被调整为:
12 8 4 0
13 9 5 1
14 10 6 2
15 11 7 3
void rotateMatrix(vector<vector<int>>& arr) {
// 设置标志点,即对角线两点
int x1 = 0, y1 = 0;
int x2 = arr.size() - 1, y2 = arr[0].size() - 1;
while (x1 < x2) { // 假如是奇数,最中心的也不需要交换位置
for (int i = 0; i < x2 - x1; i++) {// 交换位置
int temp = arr[x1][y1 + i];
arr[x1][y1 + i] = arr[x2 - i][y1];
arr[x2 - i][y1] = arr[x2][y2 - i];
arr[x2][y2 - i] = arr[x1 + i][y2];
arr[x1 + i][y2] = temp;
}
x1++;
y1++;
x2--;
y2--;
}
}
题目五判断aim是否在matrix中
给定一个元素为非负整数的二维数组matrix,每行和每列都是从小到大有序的。
再给定一个非负整数aim,请判断aim是否在matrix中。
- 从右上角还是搜索,大了往左,小了往下,直到出边界
bool inMatrix(vector<vector<int>> arr, int val) {
int i = 0;
int j = arr[0].size() - 1;
while (i <= arr.size() - 1 && j <= arr[0].size() - 1) {
int k = arr[i][j];
if (k > val) {
j--;
}
else if (k < val) {
i++;
}
else {
cout << "存在" << endl;
return true;
}
}
cout << "不存在" << endl;
return false;
}
题目六
贪心方法、质数判断、分解非质数
假设s和m初始化,s = “a”; m = s;
再定义两种操作,第一种操作:
m = s;
s = s + s;
第二种操作:
s = s + m;
求最小的操作步骤数,可以将s拼接到长度等于n
- 若n为质数,则全部调操作二为最少步骤,为n - 1。若n为质数,先前s到达了k个,则进行操作一,m = k,s = 2k,则后续s必须为k的倍数,则不成立
- n不为质数,则拆成质数的乘积,然后同理
bool isPrim(int n) { // 判断是否为质数
if (n < 2) {
return false;
}
int max = (int)sqrt((double)n);
; for (int i = 2; i < max; i++) {
if (n % i == 0) {
return false;
}
}
return true;
}
struct ReturnType {
int sum; // 不包括1的质数和
int count; // 不包括1的质数个数
ReturnType() : sum(0), count(0){}
};
ReturnType* divsSumAndCount(int n) {
ReturnType* res = new ReturnType();
for (int i = 2; i <= n; i++) { // 求解n由多少个质数构成
while (n % i == 0) {
res->sum += i;
res->count++;
n /= i;
}
}
return res;
}
int splitNbySM(int n) {
if (n < 2) {
return 0;
}
if (isPrim(n)) {
return n - 1;
}
ReturnType* res = divsSumAndCount(n);
return res->sum - res->count;
}
题目七
小根堆自定义排序
给定一个字符串类型的数组arr,求其中出现次数最多的前K个
- 大根堆,按照词频来排
- 小根堆,不得超过k个,目前为止,次数最大的前k个按小根堆组织,小根堆堆顶为“门槛”
struct cmp1 {
bool operator() (const pair<string, int>& p1, const pair<string, int>& p2) {
return p1.second < p2.second;// 大根堆
}
};
vector<string> topKTimes1(vector<string> arr, int k) {
unordered_map<string, int> umap;
vector<string> res(k);
for (int i = 0; i < arr.size(); i++) {
umap[arr[i]]++;
}
priority_queue<pair<string, int>, vector<pair<string, int>>, cmp1> que;
for (pair<string, int> p : umap) {
que.push(p);
}
for (int i = 0; i < k; i++) {
cout << que.top().first << " ";
res.push_back(que.top().first);
que.pop();
}
return res;
}
struct cmp2 {
bool operator() (const pair<string, int>& p1, const pair<string, int>& p2) {
return p1.second > p2.second;// 小根堆
}
};
vector<string> topKTimes2(vector<string> arr, int k) {
unordered_map<string, int> umap;
vector<string> res(k);
for (int i = 0; i < arr.size(); i++) {
umap[arr[i]]++;
}
priority_queue<pair<string, int>, vector<pair<string, int>>, cmp2> que;
for (pair<string, int> p : umap) {
if (que.size() < k) {
que.push(p);
}
else {
if (que.top().second < p.second) {
que.pop();
que.push(p);
}
}
}
for (int i = k - 1; i >= 0; i--) {
res[i] = que.top().first;
cout << que.top().first << " ";
que.pop();
}
return res;
}
投票并显示
自定义堆
设计一个结构,可以随时向其中加入字符串,并可以实时显示其次数top k的字符串,类似于实时投票系统
- 需要以下三种结构
- 词频表不断记录添加的字符串及其个数
- 堆个数为k个,为小根堆,堆顶为“门槛”,若没满或者大于“门槛”则可以进入,每次更新堆或更新堆中的数据时,都要进行heapify操作
- 堆位置map,记录字符串在堆的位置,若不在但出现过为-1
struct Node {
string str;
int times;
Node(string str, int times) : str(str), times(times) {}
};
class TopKRecord {
public:
unordered_map<string, Node*> strNodeMap;// 词频表
vector<Node*> heap;// 小根堆(自定义堆)
int heapSize;// 目前为止堆有多少个元素
unordered_map<Node*, int> nodeIndexMap;// 节点所在堆位置表
TopKRecord(int size) {// 最多实时显示size个最大值
this->heapSize = 0;// 目前为0个节点元素
this->heap.resize(size);
}
void add(string str) {
Node* curNode = nullptr;
int preIndex = -1;
if (!strNodeMap.count(str)) {// 不在词频表内,表示第一次出现
curNode = new Node(str, 1);// 建立新Node
strNodeMap.insert({ str, curNode });// 放入词频表中
nodeIndexMap.insert({ curNode, -1 });// 放入堆位置表中
}
else {// 词频表中存在
curNode = strNodeMap[str];
curNode->times++;
preIndex = nodeIndexMap[curNode];
}
if (preIndex == -1) {// str不在小根堆中
if (heapSize == heap.size()) {
if (curNode->times > heap[0]->times) {// 干过了
nodeIndexMap[heap[0]] = -1;
nodeIndexMap[curNode] = 0;
heap[0] = curNode;
heapify(0, heapSize);
}
}
else {// 没满直接添加进末尾,并且heapinsert
heap[heapSize] = curNode;
nodeIndexMap[curNode] = heapSize;
heapInsert(heapSize++);
}
}
else {// str在小根堆中
heapify(preIndex, heapSize);
}
}
private:
void heapify(int preIndex, int heapSize) {
int left = preIndex * 2 + 1;
int right = preIndex * 2 + 2;
while (left < heapSize) {
int largest = (right < heapSize && heap[right]->times > heap[left]->times) ? right : left;
largest = heap[largest]->times > heap[preIndex]->times ? largest : preIndex;
if (largest == preIndex) {
break;
}
swap(preIndex, largest);
preIndex = largest;
left = preIndex * 2 + 1;
right = preIndex * 2 + 2;
}
}
void heapInsert(int index) {
while ((index - 1) / 2 >= 0 && heap[index]->times < heap[(index - 1) / 2]->times) {
swap(index, (index - 1) / 2);
index = (index - 1) / 2;
}
}
void swap(int preIndex, int largest) {
nodeIndexMap[heap[preIndex]] = largest;
nodeIndexMap[heap[largest]] = preIndex;
Node* tmp = heap[preIndex];
heap[preIndex] = heap[largest];
heap[largest] = tmp;
}
};