883. 三维形体投影面积 / 剑指 Offer II 017. 含有所有字符的最短字符串

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;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值