题目描述:
你的面前有一堵方形的、由多行砖块组成的砖墙。 这些砖块高度相同但是宽度不同。你现在要画一条自顶向下的、穿过最少砖块的垂线。
砖墙由行的列表表示。 每一行都是一个代表从左至右每块砖的宽度的整数列表。
如果你画的线只是从砖块的边缘经过,就不算穿过这块砖。你需要找出怎样画才能使这条线穿过的砖块数量最少,并且返回穿过的砖块数量。
你不能沿着墙的两个垂直边缘之一画线,这样显然是没有穿过一块砖的。
示例:
提示:
- 每一行砖块的宽度之和应该相等,并且不能超过 INT_MAX。
- 每一行砖块的数量在 [1,10,000] 范围内, 墙的高度在 [1,10,000] 范围内, 总的砖块数量不超过 20,000。
题意:
一个二维vector中的每一行总和都是一样的,将每个数字形象化为砖块的话,考虑怎样能穿过最少的砖块。
其实一开始已经提到了总和,应该从数字和这个角度考虑。
用上面的示例举例,假想有一条线正在从左往右开始移动,它能移动的位置有以下几种选择,黑色的线是我贴加上去的。
看第3条黑线,它满足有3行在黑线前面的数字和是一样的值都为3,分别是第一行、第二行、第四行,这也意味着黑线穿过了6-3=3行,
而后的红线按照同样的道理,第二行、第三行、第五行、第六行在红线前面的数字和都一样为4,而红线相比其他黑线穿过的砖块更少,所以最后作为输出6-4=2.
由此看来解题的关键就在怎么判断每一条可划线之前相同的数字和出现的次数d,用总行数row-d得到最小的那个数字即为输出。
讲到这里应该可以想到 对每行计算可获得数字和,并统计在所有行中这些数字和出现的次数。
比如第一行可获得的数字和为1,3,5,6;(由于每行最后都能获得数字6,在实际算法中应该将获得数字6的运算去掉以降低开销)
第二行可获得的数字和为3,4,6;
第三行可获得的数字和为1,4,6;
第四行可获得的数字和为2,6;
第五行可获得的数字和为3,4,6;
第六行可获得的数字和为1,4,5,6;
统计一下,发现1出现3次,意味着可以找到一条黑线(也就是上面的第一条)前面的数字和为1,且黑线没有穿过砖块的行数为3;
2出现1次,对应上面的第二条黑线前面的数字和为2,且黑线没有穿过砖块的行数为1;依次类推。
代码:
1 class Solution{ 2 public: 3 map<int, int> mapping; 4 int leastBricks(vector<vector<int>>& wall) { 5 int row = wall.size(); //wall的高度 6 int backnum = row; 7 8 for(int i = 0; i < row; i++) 9 { 10 vector<int> line = wall[i]; 11 int sum = 0; 12 for(int j = 0; j < line.size() - 1; j++) 13 { 14 sum += line[j]; 15 if(mapping.find(sum) == mapping.end()) 16 mapping[sum] = 1; 17 else 18 mapping[sum]++; 19 } 20 } 21 22 //process 23 for(auto i : mapping) 24 { 25 int ans = row - i.second; 26 if(ans < backnum) 27 backnum = ans; 28 } 29 return backnum; 30 } 31 };
不足:
建立的map映射开销颇大,可能需要换一种映射策略。