883. 三维形体投影面积【简单题】【每日一题】
思路:
这题我感觉最大的难点是看懂题目表达的意思,写一下我的理解。
矩阵grid有若干行和若干列,每一行对应x坐标,每行的每一列对应y坐标,值代表z坐标,拿测试用例1来说,grid = {{1,2},{3,4}},表示三维体在x-y平面坐标(0,0)位置高度为1,(0,1)位置高度为2,(1,0)位置高度为3,(1,1)位置高度为4。
理解输入是什么意思之后就就三视图的面积就是水到渠成的事情,下面发个分离版和整合版的,可能测试数据量太小,耗时相同,均为2ms。
代码:
class Solution {
public int projectionArea(int[][] grid) {
int ans = 0;
//俯视图 x-y grid[i][j]中每个值只要不为0,统统算1,累加
for (int[] ints : grid) {
for (int i : ints) {
if (i != 0){
ans++;
}
}
}
//主视图 z-y 每个grid[i][j]中每一行中的最大值,累加
for (int[] ints : grid) {
int max = 0;
for (int i : ints) {
max = Math.max(max,i);
}
ans += max;
}
//侧视图 z-x grid[i][j]中每一列中的最大值,累加
int c = grid[0].length;
for (int i = 0; i < c; i++) {
int max = 0;
for (int[] ints : grid) {
max = Math.max(max, ints[i]);
}
ans += max;
}
return ans;
}
}
class Solution {
public int projectionArea(int[][] grid) {
int ans = 0,r = grid.length,c = grid[0].length;
//俯视图 x-y grid[i][j]中每个值只要不为0,统统算1,累加
//主视图 z-y 每个grid[i][j]中每一行中的最大值 maxRow,累加
//侧视图 z-x grid[i][j]中每一列中的最大值 maxCol,累加
for (int i = 0; i < r; i++) {
int maxRow = 0,maxCol = 0;
for (int j = 0; j < c; j++) {
if (grid[i][j] != 0){
ans++;
}
maxRow = Math.max(maxRow,grid[i][j]);
maxCol = Math.max(maxCol,grid[j][i]);
}
ans += maxRow;
ans += maxCol;
}
return ans;
}
}
剑指 Offer II 017. 含有所有字符的最短字符串【困难题】
思路:【滑动窗口】
还是滑动窗口,滑就完事了。
还是用数组记录每个字符出现的频次,需要注意的是这里题目要求说的是字符是英文字母,不区分大小写,因此需要将它们全部统计进去,为了统计方便,ASCII
表中小写字母和大写字母之间的字符也需要占位,因此需要开辟长度为58
的空间统计字符频次。
自定义judge
函数,用来判断当前窗口字符串是否包含字符串t
的所有字符,具体实现为,传入当前窗口字符串字符的统计频次数组cnts
和字符串t
的统计频次数组cntt
,如果cnts
的每一位都大于等于cnts
,那么说明当前窗口字符串符合条件,否则说明不符合条件。
先记录字符串t的字符频次,然后记录字符串s
的前nt
(nt
为t的长度)个字符频次,如果这就符合条件了,就直接返回这个子字符串,它必然是长度最短的。如果不是,那么就固定左边界left
(初始为0
),不断右移右边界,并判断是否符合条件,当符合条件时,固定右边界i
,将左边界left
对应的字符频次减1
,并不断右移左边界left
,直到条件不成立为止,此时我们就找到了当前右边界对应的符合条件的子串的最短长度,并与全局的最短子串长度进行比较,更新最短子串和最短长度。
代码:
class Solution {
public String minWindow(String s, String t) {
int ns = s.length(),nt = t.length();
if (ns < nt){
return "";
}
int[] cnts = new int[58], cntt = new int[58];
//记录t中每个字符出现的频次
char[] cs = s.toCharArray(), ct = t.toCharArray();
for (char c : ct) {
cntt[c-'A']++;
}
for (int i = 0; i < nt; i++) {//求出s中substring(0,nt)子串中每个字符出现频次
cnts[cs[i]-'A']++;
}
if (judge(cnts,cntt)){
//根据题意,符合题意的子字符串至少要跟t一样长
// 于是这一个长度为nt的窗口如果符合题意,那么它肯定是最短的,直接返回即可
return s.substring(0,nt);
}
//如果不符合条件,则固定窗口左边界为0,不断扩大右边界,直到符合条件为止
int left = 0,min = Integer.MAX_VALUE;
String ans = "";
for (int i = nt; i < ns ; i++) {
cnts[cs[i]-'A']++;
if (judge(cnts,cntt)){//如果遇到符合条件的子串
//固定窗口右边界为 i,从左边界起点开始,不断将左边界右移,并判断是否依然符合条件
while (judge(cnts,cntt)){
cnts[cs[left++]-'A']--;
}
//当左边界移动到条件失效时,说明找到了一个目标最短窗口[left-1,i],长度为 i-left+1
//对最短字符串进行更新
if (i-left+1 < min){
min = i-left+1;
ans = s.substring(left-1,i+1);
}
}
}
return ans;
}
public boolean judge(int[] c1,int[] c2){
int n = c1.length;
for (int i = 0; i < n; i++) {
if (c1[i] < c2[i]){
return false;
}
}
return true;
}
}