Leetcode 第401,412,414,434,441,448,453,459,463,482题(Java解法)

第401题 二进制手表

二进制手表顶部有 4 个 LED 代表 小时(0-11),底部的 6 个 LED 代表 分钟(0-59)。每个 LED 代表一个 0 或 1,最低位在右侧。
给你一个整数 turnedOn ,表示当前亮着的 LED 的数量,返回二进制手表可以表示的所有可能时间。你可以 按任意顺序 返回答案。
小时不会以零开头:
例如,“01:00” 是无效的时间,正确的写法应该是 “1:00” 。
分钟必须由两位数组成,可能会以零开头:
例如,“10:2” 是无效的时间,正确的写法应该是 “10:02” 。

示例 1:

输入输出
turnedOn = 1[“0:01”,“0:02”,“0:04”,“0:08”,“0:16”,“0:32”,“1:00”,“2:00”,“4:00”,“8:00”]

示例 2:

输入输出
turnedOn = 9[]

解题思路

让小时和分钟都从0开始遍历,如果有满足条件的时钟和分钟,则加入结果

代码

// 二进制手表:枚举
class Solution {
    public List<String> readBinaryWatch(int turnedOn) {
        List<String> ans = new ArrayList<String>();
        for (int h = 0; h < 12; ++h) {
            for (int m = 0; m < 60; ++m) {//小时从0开始遍历,分钟从0开始遍历
                if (Integer.bitCount(h) + Integer.bitCount(m) == turnedOn) {//如果所需的比特位符合,则加入结果中
                    ans.add(h + ":" + (m < 10 ? "0" : "") + m);
                }
            }
        }
        return ans;
    }
}

时间复杂度为O(1)
空间复杂度为O(1)

第412题 Fizz Buzz/font>

**写一个程序,输出从 1 到 n 数字的字符串表示。

  1. 如果 n 是3的倍数,输出“Fizz”;
  2. 如果 n 是5的倍数,输出“Buzz”;
    3.如果 n 同时是3和5的倍数,输出 “FizzBuzz”。**

示例 1:

输入输出
n = 15[ “1”,“2”,“Fizz”, “4”,“Buzz”,“Fizz”,“7”,“8”,“Fizz”,“Buzz”, “11”,“Fizz”,“13”,“14”,“FizzBuzz”]

解题思路

本题直接遍历判断

代码

// Fizz Buzz:遍历
class Solution {
  public List<String> fizzBuzz(int n) {
    List<String> ans = new ArrayList<String>();//定义一个输出结果为字符串类型
    for (int num = 1; num <= n; num++) {
      boolean divisibleBy3 = (num % 3 == 0);//判断能否被3整除
      boolean divisibleBy5 = (num % 5 == 0);//判断能否被5整除
      if (divisibleBy3 && divisibleBy5) {
        ans.add("FizzBuzz");
      } else if (divisibleBy3) {
        ans.add("Fizz");
      } else if (divisibleBy5) {
        ans.add("Buzz");
      } else {
        ans.add(Integer.toString(num));
      }//4种情况加入到结果中
    }
    return ans;
  }
}

时间复杂度为O(n),n为数字的大小
空间复杂度为O(1)

第414题 第三大的数

给你一个非空数组,返回此数组中 第三大的数 。如果不存在,则返回数组中最大的数。

示例 1:

输入输出
[3, 2, 1]1

示例 2:

输入输出
[1, 2]2

解释:第三大的数不存在, 所以返回最大的数 2 。

示例 3:

输入输出
[2, 2, 3, 1]1

解释:注意,要求返回第三大的数,是指在所有不同数字中排第三大的数。
此例中存在两个值为 2 的数,它们都排第二。在所有不同数字中排第三大的数为 1 。

解题思路

遍历数组,设三个变量,从大到小分别为max1,max2,max3,每遍历到1个数,就从max1比较,如果比max1就更新max1为该数,然后让max2等于max1,max3等于max2,按这种规则比较更新。

代码

// 第三大的数:数组
class Solution {
    public int thirdMax(int[] nums) {
        long max1 = Long.MIN_VALUE, max2 = Long.MIN_VALUE, max3 = Long.MIN_VALUE;
        for (int num : nums) {//遍历数组
            if (num == max1 || num == max2 || num == max3) continue;//当遍历到的数等于三个数之一,则跳过该数,继续遍历
            if (num > max1) {//如果有一个数比最大的max1还大,则从大到小更新这三个数
                max3 = max2;
                max2 = max1;
                max1 = num;
            } else if (num > max2) {//如果在第一大和第二大之间,则从第二大的数往下更新
                max3 = max2;
                max2 = num;
            } else if (num > max3) {//如果只大于第三大的数,则更新第三大的数
                max3 = num;
            }
        }
        return (int) (max3 == Long.MIN_VALUE ? max1 : max3);//如果第三大的数是原始值,则返回第一大的值
    }
}

时间复杂度为O(n),n为数组的长度
空间复杂度为O(1)

第434题 字符串中的单词数

统计字符串中的单词个数,这里的单词指的是连续的不是空格的字符。
请注意,你可以假定字符串里不包括任何不可打印的字符。

示例 1:

输入输出
“Hello, my name is John”5

解释: 这里的单词是指连续的不是空格的字符,所以 “Hello,” 算作 1 个单词。

解题思路

如果字符串遍历到的下一位置不为空时,如果当前位置为起始位置或者为空格,则代表之前有一个单词,否则就继续遍历,不记录单词。

代码

// 字符串中的单词数:
class Solution {
    public int countSegments(String s) {
        int segmentCount = 0;//统计单词数
        for (int i = 0; i < s.length(); i++) {//遍历字符串
            if ((i == 0 || s.charAt(i-1) == ' ') && s.charAt(i) != ' ') {//当字符串遍历到的当前字符的下一个字符不为空时,如果第一个遍历到的是单词,则记为1个单词,如果是空格,也记为1个单词
                segmentCount++;
            }
        }
        return segmentCount;
    }
}

时间复杂度为O(n),n为字符串的长度
空间复杂度为O(1)

第441题 排列硬币

你总共有 n 枚硬币,你需要将它们摆成一个阶梯形状,第 k 行就必须正好有 k 枚硬币。
给定一个数字 n,找出可形成完整阶梯行的总行数。
n 是一个非负整数,并且在32位有符号整型的范围内。

示例 1:

输入输出
n = 52

解释:因为第三行不完整,所以返回2.

示例 2:

输入输出
n = 83

解释:因为第四行不完整,所以返回3.

解题思路

利用等差数列可得k(k+1)/2=n,可解出k。

代码

// 排列硬币:数学
class Solution {
    public int arrangeCoins(int n) {
        return (int)(Math.sqrt(2) * Math.sqrt(n + 0.125) - 0.5);
    }
}

时间复杂度为O(1)
空间复杂度为O(1)

第448题 找到所有数组中消失的数字

给你一个含 n 个整数的数组 nums ,其中 nums[i] 在区间 [1, n] 内。请你找出所有在 [1, n] 范围内但没有出现在 nums 中的数字,并以数组的形式返回结果。

示例 1:

输入输出
nums = [4,3,2,7,8,2,3,1][5,6]

示例 2:

输入输出
nums = [1,1][2]

解题思路

遍历数组,将数组加入哈希表中,然后从头遍历哈希表,如果当前遍历到的下标比数字大或者相等,则将该下标加1作为一个输出结果。

代码

// 找到所有数组中消失的数字:哈希表
class Solution {
    public List<Integer> findDisappearedNumbers(int[] nums) {
        int n = nums.length;
        for (int num : nums) {//遍历哈希表
            int x = (num - 1) % n;//将遍历到的数字存入对应的下标,因为有下标0,所以将数字减1
            nums[x] += n;
        }
        List<Integer> ret = new ArrayList<Integer>();
        for (int i = 0; i < n; i++) {
            if (nums[i] <= n) {
                ret.add(i + 1);//如果当前遍历到的数小于或等于当前下标,则将当前下标加1即数组中不存在的数加入输出结果中
            }
        }
        return ret;
    }
}

时间复杂度为O(n),n为数组的长度
空间复杂度为O(1)

第453题 最小操作次数使数组元素相等

给定一个长度为 n 的 非空 整数数组,每次操作将会使 n - 1 个元素增加 1。找出让数组所有元素相等的最小操作次数。

示例 1:

输入输出
[1,2,3]3

解释:
只需要3次操作(注意每次操作会增加两个元素的值):
[1,2,3] => [2,3,3] => [3,4,3] => [4,4,4]

解题思路

每一次移动都会让n-1个元素加1,就等价于让一个元素减小,所以让所有元素都等于最小的那个元素,就等同于让所有元素相等。

代码

// 最小操作次数使数组元素相等:数学
public class Solution {
    public int minMoves(int[] nums) {
        int moves = 0, min = Integer.MAX_VALUE;
        for (int i = 0; i < nums.length; i++) {
            min = Math.min(min, nums[i]);
        }//找出最小元素
        for (int i = 0; i < nums.length; i++) {
            moves += nums[i] - min;
        }//计算每个元素与最小元素的差值
        return moves;
    }
}

时间复杂度为O(n),m,n为数组的长度
空间复杂度为O(1)

第459题 重复的子字符串

给定一个非空的字符串,判断它是否可以由它的一个子串重复多次构成。给定的字符串只含有小写英文字母,并且长度不超过10000。

示例 1:

输入输出
“abab”true

解释: 可由子字符串 “ab” 重复两次构成。

示例 2:

输入输出
“aba”false

示例 3:

输入输出
“abcabcabcabc”true

解释: 可由子字符串 “abc” 重复四次构成。 (或者子字符串 “abcabc” 重复两次构成。)

解题思路

kmp算法,简单来讲就是在移动进行匹配时,假设一个一个比较遇见了不匹配的字符,但是在模式串后段出现了与前段相同的字符,则定义了一个next数组,这个数组存储了满足下列要求的最大值。然后利用这个最大值可以跳过一些一定不会匹配的下标,节省时间

代码

// 重复的子字符串:KMP算法
class Solution {
    public boolean repeatedSubstringPattern(String s) {
        return kmp(s);
    }
    public boolean kmp(String pattern) {
        int n = pattern.length();//模式串
        int[] fail = new int[n];//等同于next数组
        Arrays.fill(fail, -1);
        for (int i = 1; i < n; ++i) {
            int j = fail[i - 1];//用j先存储前一个数的next值
            while (j != -1 && pattern.charAt(j + 1) != pattern.charAt(i)) {
                j = fail[j];//如果与模式串不匹配,则存入-1
            }
            if (pattern.charAt(j + 1) == pattern.charAt(i)) {//如果首尾字母匹配,则将当前下标设为首部匹配的最后一个字母的下标位
                fail[i] = j + 1;
            }
        }
        return fail[n - 1] != -1 && n % (n - fail[n - 1] - 1) == 0;//最后一个字母的匹配值为-1,代表不匹配,n为0,代表字符串为空,如果最后一个字母的匹配值刚好等于它的下标则代表都匹配
    }
}

时间复杂度为O(n),n为字符串的大小
空间复杂度为O(n)

第463题 岛屿的周长

给定一个 row x col 的二维网格地图 grid ,其中:grid[i][j] = 1 表示陆地, grid[i][j] = 0 表示水域。
网格中的格子 水平和垂直 方向相连(对角线方向不相连)。整个网格被水完全包围,但其中恰好有一个岛屿(或者说,一个或多个表示陆地的格子相连组成的岛屿)。
岛屿中没有“湖”(“湖” 指水域在岛屿内部且不和岛屿周围的水相连)。格子是边长为 1 的正方形。网格为长方形,且宽度和高度均不超过 100 。计算这个岛屿的周长。

示例 1:
在这里插入图片描述

输入输出
grid = [[0,1,0,0],[1,1,1,0],[0,1,0,0],[1,1,0,0]]16

解释:它的周长是上面图片中的 16 个黄色的边

示例 2:

输入输出
grid = [[1]]4

示例 3:

输入输出
grid = [[1,0]]4

解题思路

迭代每一个格子,判断四周是否有水域

代码

// 岛屿的周长:迭代
class Solution {
    static int[] dx = {0, 1, 0, -1};
    static int[] dy = {1, 0, -1, 0};//dx与dy分别对应4个方向
    public int islandPerimeter(int[][] grid) {
        int n = grid.length, m = grid[0].length;
        int ans = 0;
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < m; ++j) {
                if (grid[i][j] == 1) {//判断是否为陆路
                    int cnt = 0;//先定义当前格子的周长为0
                    for (int k = 0; k < 4; ++k) {
                        int tx = i + dx[k];
                        int ty = j + dy[k];
                        if (tx < 0 || tx >= n || ty < 0 || ty >= m || grid[tx][ty] == 0) {
                            cnt += 1;//当tx和ty中有一个小于0或大于n或者m代表这个边在边界上,一定可以计算为周长,或者这个方向上的格子为水,也算作周长
                        }
                    }
                    ans += cnt;//统计所有周长
                }
            }
        }
        return ans;
    }
}

时间复杂度为O(mn),m,n为二维网格的长和宽
空间复杂度为O(1)

第482题 密钥格式化

有一个密钥字符串 S ,只包含字母,数字以及 ‘-’(破折号)。其中, N 个 ‘-’ 将字符串分成了 N+1 组。
给你一个数字 K,请你重新格式化字符串,使每个分组恰好包含 K 个字符。特别地,第一个分组包含的字符个数必须小于等于 K,但至少要包含 1 个字符。两个分组之间需要用 ‘-’(破折号)隔开,并且将所有的小写字母转换为大写字母。
给定非空字符串 S 和数字 K,按照上面描述的规则进行格式化。

示例 1:

输入输出
S = “5F3Z-2e-9-w”, K = 4“5F3Z-2E9W”

解释:字符串 S 被分成了两个部分,每部分 4 个字符;
注意,两个额外的破折号需要删掉。

示例 2:

输入输出
S = “2-5g-3-J”, K = 2“2-5G-3J”

解释:字符串 S 被分成了 3 个部分,按照前面的规则描述,第一部分的字符可以少于给定的数量,其余部分皆为 2 个字符。

解题思路

先去除破折号,并将小写字母转大写字母,然后从后向前遍历,每当有一个字符串达到上限个数,就加入一个破折号,继续向前遍历,最后反向输出字符串即可。

代码

// 密钥格式化:
class Solution {
    public String licenseKeyFormatting(String S, int K) {
    //删除破折号,并转大写
    S = S.replace("-", "").toUpperCase();
    StringBuilder sb = new StringBuilder();
    int cnt = 0;
    //倒序遍历
    for (int i = S.length() - 1; i >= 0; i--) {
        sb.append(S.charAt(i));
        cnt++;
        //如果满了K个字符并且i不是0时,加上破折号
        if (cnt % K == 0 && i != 0) {
            sb.append("-");
        }
    }
    //因为是倒序遍历,所以最后需要翻转下字符串
    return sb.reverse().toString();
    }
}

笔记:toUpperCase():将小写字符转换为大写字符;replace()是替换函数

时间复杂度为O(n),n为字符串长度
空间复杂度为O(n)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值