leetcode2

1. 520. 检测大写字母

2. 643. 子数组最大平均数 I

 

520. 检测大写字母

给定一个单词,你需要判断单词的大写使用是否正确。

我们定义,在以下情况时,单词的大写用法是正确的:

全部字母都是大写,比如"USA"。
单词中所有字母都不是大写,比如"leetcode"。
如果单词不只含有一个字母,只有首字母大写, 比如 "Google"。
否则,我们定义这个单词没有正确使用大写字母。

解题思路1:
首先遍历字符串所有字符,统计大写字母个数。
然后分三种情况:
1.大写字母个数为0,或者大写字母个数为字符串长度,说明此时为全大写或者全小写,返回true。
2.首字母大写,大写字母个数为1,说明此时只有首字母大写,返回true。

class Solution {
    public boolean detectCapitalUse(String word) {
        int len = word.length();
        int count = 0;
        for (int i = 0; i < len; i++) {
            char s = word.charAt(i);
            if (s >= 'A' && s <= 'Z') {
                count++;
            }
        }
        return count == len || count == 0
            || (count == 1 && word.charAt(0) >= 'A' && word.charAt(0) <= 'Z');
    }
}

解题思路2:

首先,判断除第一位字符之外的 所有字符的大小写情况,

然后,再判断第一位字符是否为小写字符,是的话,如果第一步判断cnt==0,则说明为全小写,返回true;

如果,第一位字符为大写字符,如果第一步判断cnt==0,则说明为首字母大写,其余为小写,返回true;

最后,如果cnt==w.length()-1,则说明第一位字符为大写字符,其余也为大写字符,是全大写,返回true;

class Solution { //输入是由大写和小写拉丁字母组成的非空单词:A或a也返回true
    public boolean detectCapitalUse(String w) { //aN返回false
        int cnt=0,i=w.length();
        while(i-->1)if(w.charAt(i)<='Z'&&w.charAt(i)>='A')cnt++; //Z在前更好
        if(w.charAt(0)>='a'&&w.charAt(0)<='z')return cnt==0; //a在前更好
        else return cnt==0||cnt==w.length()-1;
    }
}

说明:

(1) ASCII编码 A~Z,65~90为,a~z为97~122。所以 Z 在前更好;a在前更好;

(2) while(i-->1)你可以看做是这样的表达式((i--)>1) ;也就是说先直接拿变量i中的值出来与1做比较,发现如果条件为真,则立刻执行循环体1次,"之后再将变量i中的值减1,然后再拿这个减过后的值如1做比较,如果结果为真,再执行循环体中语句,为假则退出...以此类推" ;但是,有个问题你要注意一下,如果当i为1时候,1>1结果为假,跳出循环,但是后面那个自减运算还是要做一次的,也就是说退出之后i中的值为0而不再是1了,这个与函数的内存布局有关,简单的说是运行stack的问题.

(3) java中length和length()的区别? 在java中String类可以定义字符串变量和字符串数组,length()用于求String字符串对象的长度,而length用于求String字符串数组的长度。注意,是长度 不是 下标,下标从零开始计算,长度是从1开始计算;

class Solution { //输入是由大写和小写拉丁字母组成的非空单词:A或a也返回true
    public boolean detectCapitalUse(String w) { //aN返回false
        int cnt=0,i=w.length();
        while(i-->1)if(w.charAt(i)<='Z')cnt++; //输入是由大写和小写拉丁字母组成的非空单词
        return cnt==0||cnt==w.length()-1&&w.charAt(0)<='Z';
    }
}

643. 子数组最大平均数 I

给定 n 个整数,找出平均数最大且长度为 k 的连续子数组,并输出该最大平均数。 

方法一:滑动窗口
由于规定了子数组的长度为 k,因此可以通过寻找子数组的最大元素和的方式寻找子数组的最大平均数,元素和最大的子数组对应的平均数也是最大的。证明如下:

假设两个不同的子数组的长度都是 k,
这两个子数组的元素和分别是 x 和 y,
则这两个子数组的平均数分别是 x/k 和 y/k。
如果 x≥y,则有 x/k≥y/k,
即如果一个子数组的元素和更大,则该子数组的平均数也更大。
为了找到子数组的最大元素和,
需要对数组中的每个长度为 k 的子数组分别计算元素和。
对于长度为 n 的数组,当 k≤n 时,有 n-k+1 个长度为 k 的子数组。//除第一个包含k个元素的数组外,还有n-k个数,n-k+1,这个1代表第一个k个元素的数组;
如果直接计算每个子数组的元素和,
则时间复杂度过高,无法通过全部测试用例,
因此需要使用时间复杂度更低的方法计算每个子数组的元素和。

用 sumi 表示数组 nums 以下标 i 结尾的长度为 k 的子数组的元素和,
其中 i≥k−1,则 sumi 的计算方法如下://i为数组的下标,下标会从0开始,比数组个数少1;

说明:

(1) 用 sumi 表示数组 nums 以下标 i 结尾的长度为 k 的子数组的元素和;因为下标从0开始,所以i会比k少1,i-k=-1,数组的第一个元素应该为0,所以为i-k+1;

上述过程可以看成维护一个长度为 kk 的滑动窗口。
当滑动窗口从下标范围 [i−k,i−1] 移动到下标范围 [i−k+1,i] 时,
nums[i−k] 从窗口中移出,nums[i] 进入到窗口内。
利用上述关系,可以在 O(1) 的时间内通过 sum i−1 得到 sumi 。

第一个子数组的元素和 sum k−1 需要通过计算 nums 的前 k 个元素之和得到,
从 sumk 到 sum n−1 的值则可利用上述关系快速计算得到。
只需要遍历数组 nums 一次即可得到每个长度为 k 的子数组的元素和,
时间复杂度是 O(n)。

在上述过程中维护最大的子数组元素和,记为 maxSum,
子数组的最大平均数即为 maxSum/k。
需要注意返回值是浮点型,因此计算除法时需要进行数据类型转换。
class Solution {
    public double findMaxAverage(int[] nums, int k) {
        int sum = 0;
        int n = nums.length;
        for (int i = 0; i < k; i++) {
            sum += nums[i];
        }
        int maxSum = sum;
        for (int i = k; i < n; i++) {
            sum = sum - nums[i - k] + nums[i];
            maxSum = Math.max(maxSum, sum);
        }
        return 1.0 * maxSum / k;
    }
}

 方法二:还可以只写一个 for 循环:

class Solution {
    public double findMaxAverage(int[] nums, int k) {
        if (k > nums.length || nums.length == 0) {
            return 0.0;
        }
        double sum = 0;
        double maxSum = 0;
        for (int j = 0; j < nums.length; ++j) {
            if (j < k) {
                sum += nums[j];
                continue;
            }
            maxSum = Math.max(maxSum,sum);
            sum = sum + nums[j] - nums[j-k];
            
        }
        maxSum = Math.max(maxSum,sum);
        return maxSum / k;
    }
}

说明:

(1) continue:强迫一个循环提早反复时使用。也就是,你可能想要继续运行循环,但是要忽略这次重复剩余的循环体的语句。

continue 语句是break语句的补充。
在while 和do while 循环中,continue 语句使控制直接转移给控制循环的条件表达式,然后继续循环过程。
在for 循环中,循环的反复表达式被求值,然后执行条件表达式,循环继续执行。
对于这3种循环,任何中间的代码将被旁路。

示例 1 : continue:如果是双数,后面的代码不执行,直接进行下一次循环

 

public class HelloWorld {
    public static void main(String[] args) {
        //打印单数    
        for (int j = 0; j < 10; j++) {
            if(0==j%2) 
                continue; //如果是双数,后面的代码不执行,直接进行下一次循环
            System.out.println(j);
        }
    }
}

方法三:滑动窗口解法(模板)

 以下代码,可以作为滑动窗口模板使用:

  1. 初始化将滑动窗口压满,取得第一个滑动窗口的目标值

  2. 继续滑动窗口,每往前滑动一次,需要删除一个和添加一个元素

class Solution {
    public double findMaxAverage(int[] nums, int k) {
        double ans = 0, sum = 0;
        for (int i = 0; i < k; i++) sum += nums[i];
        ans = sum / k;
        for (int i = k; i < nums.length; i++) {
            sum = sum + nums[i] - nums[i - k]; // int add = nums[i], del = nums[i - k];
            ans = Math.max(ans, sum / k);
        }
        return ans;
    }
}

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/detect-capital
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

原文地址:https://www.cnblogs.com/HarryVan/p/14424322.html