文章目录
前言
需要开通vip的题目暂时跳过
笔记导航
点击链接可跳转到所有刷题笔记的导航链接
263. 丑数
编写一个程序判断给定的数是否为丑数。
丑数就是只包含质因数 2, 3, 5 的正整数。
-
解答
public boolean isUgly(int num) { if(num <= 0)return false; if(num == 1)return true; if(num % 5 == 0)return isUgly(num/5); if(num % 3 == 0)return isUgly(num/3); if(num % 2 == 0)return isUgly(num/2); return false; }
-
分析
- 递归出口,小于等于0的直接返回false
- 等于1的时候返回true;
- 依次将num除以5、3、2 看哪个可以整除,就执行递归
- 若无法整除5、3、2,说明存在其他质数
-
提交结果
264.丑数 II
编写一个程序,找出第 n
个丑数。
丑数就是质因数只包含 2, 3, 5
的正整数。
- 解答
//方法一
public int nthUglyNumber(int n) {
long[] ugly = new long[1690];
PriorityQueue<Long> queue = new PriorityQueue<>();
HashSet<Long> set = new HashSet<>();
queue.add(1L);
set.add(1L);
int[] numbers = {2,3,5};
for(int i = 0;i < 1690;i++){
long current = queue.poll();
ugly[i] = current;
for(int number : numbers){
if(!set.contains(current * number)){
set.add(current*number);
queue.add(current*number);
}
}
}
return (int)ugly[n-1];
}
//方法二
class Ugly {
public int[] nums = new int[1690];
Ugly() {
HashSet<Long> seen = new HashSet();
PriorityQueue<Long> heap = new PriorityQueue<Long>();
seen.add(1L);
heap.add(1L);
long currUgly, newUgly;
int[] primes = new int[]{2, 3, 5};
for(int i = 0; i < 1690; ++i) {
currUgly = heap.poll();
nums[i] = (int)currUgly;
for(int j : primes) {
newUgly = currUgly * j;
if (!seen.contains(newUgly)) {
seen.add(newUgly);
heap.add(newUgly);
}
}
}
}
}
class Solution {
public static Ugly u = new Ugly();
public int nthUglyNumber(int n) {
return u.nums[n - 1];
}
}
//方法三
class Ugly{
int[] numbers = new int[1690];
Ugly(){
numbers[0] = 1;
int i2 = 0,i3 = 0,i5 = 0;
int ugly = 1;
for(int i = 1;i<1690;i++){
ugly = Math.min(Math.min(numbers[i2] * 2,numbers[i3] * 3),numbers[i5]*5);
numbers[i] = ugly;
if(ugly == numbers[i2]*2) ++i2;
if(ugly == numbers[i3]*3) ++i3;
if(ugly == numbers[i5]*5) ++i5;
}
}
}
class Solution {
public int nthUglyNumber(int n) {
Ugly ugly = new Ugly();
return ugly.numbers[n-1];
}
}
-
分析
- 预计算 1690 个丑数:
初始化预计算用到的数组 nums,堆 queue 和哈希表 set 跟踪在堆中出现过的元素,避免重复。 - 循环计算丑数,每个步骤:
弹出堆中最小的数字 k 并添加到数组 nums 中。
若 2k,3k,5k 不存在在哈希表中,则将其添加到栈中并更新哈希表。
返回在数组中预先计算好的丑数。 - 方法二 则是将预计算的操作只进行一次,存在一个静态变量里。
- 方法三使用动态规划,利用三个指针,分别来得到当前的最小丑数。并移动指针。
- 预计算 1690 个丑数:
-
提交结果
方法一
方法二
方法三
268.缺失数字
给定一个包含 0, 1, 2, ..., n
中 n 个数的序列,找出 0 … n 中没有出现在序列中的那个数。
-
解答
//方法一 public int missingNumber(int[] nums) { Arrays.sort(nums); int len = nums.length; for(int i = 0;i<len;i++){ if(i != nums[i])return i; } return len; } // 方法二 public int missingNumber(int[] nums) { int len = nums.length; int numbers[] = new int[len + 1]; for(int i = 0;i<len;i++){ numbers[nums[i]] = 1; } for(int i = 0;i < len + 1;i++){ if(numbers[i] == 0)return i; } return -1; } //方法三 public int missingNumber(int[] nums) { int len = nums.length; int res = len; for(int i = 0;i<len;i++){ res = res^i^nums[i]; } return res; }
-
分析
- 方法一 先排序,然后遍历寻找不连续的点,即没有出现的值。
- 方法二空间换时间,用一个数组来记录出现过的数字,对应位置设为1,然后在遍历这个数组,找出没有出现过的数字。方法二的数组可以用哈希表替代。
- 方法三用异或来实现,两个相同的数字异或结果为0.假设nums的大小为10,那么将0-10和数组中的所有数字进行异或,就可以找出数组中没有出现过的数字。因为若数组中有这个数字,则表明出现过两次,则结果为0.所以最后异或的结果就是没有出现在数组中的数字,
-
提交结果
方法一
方法二
方法三
273. 整数转换英文表示
将非负整数转换为其对应的英文表示。可以保证给定输入小于 231 - 1 。
- 解答
public String one(int num) {
switch(num) {
case 1: return "One";
case 2: return "Two";
case 3: return "Three";
case 4: return "Four";
case 5: return "Five";
case 6: return "Six";
case 7: return "Seven";
case 8: return "Eight";
case 9: return "Nine";
}
return "";
}
public String twoLessThan20(int num) {
switch(num) {
case 10: return "Ten";
case 11: return "Eleven";
case 12: return "Twelve";
case 13: return "Thirteen";
case 14: return "Fourteen";
case 15: return "Fifteen";
case 16: return "Sixteen";
case 17: return "Seventeen";
case 18: return "Eighteen";
case 19: return "Nineteen";
}
return "";
}
public String ten(int num) {
switch(num) {
case 2: return "Twenty";
case 3: return "Thirty";
case 4: return "Forty";
case 5: return "Fifty";
case 6: return "Sixty";
case 7: return "Seventy";
case 8: return "Eighty";
case 9: return "Ninety";
}
return "";
}
public String two(int num) {
if (num == 0)
return "";
else if (num < 10)
return one(num);
else if (num < 20)
return twoLessThan20(num);
else {
int tenner = num / 10;
int rest = num - tenner * 10;//个位数
if (rest != 0)
return ten(tenner) + " " + one(rest);
else
return ten(tenner);
}
}
public String three(int num) {
int hundred = num / 100;//百位数
int rest = num - hundred * 100;//个位十位
String res = "";
if (hundred * rest != 0)
res = one(hundred) + " Hundred " + two(rest);
else if ((hundred == 0) && (rest != 0))
res = two(rest);
else if ((hundred != 0) && (rest == 0))
res = one(hundred) + " Hundred";
return res;
}
public String numberToWords(int num) {
if (num == 0)
return "Zero";
int billion = num / 1000000000;
int million = (num - billion * 1000000000) / 1000000;
int thousand = (num - billion * 1000000000 - million * 1000000) / 1000;
int rest = num - billion * 1000000000 - million * 1000000 - thousand * 1000;
String result = "";
if (billion != 0)
result = three(billion) + " Billion";
if (million != 0) {
if (! result.isEmpty())
result += " ";
result += three(million) + " Million";
}
if (thousand != 0) {
if (! result.isEmpty())
result += " ";
result += three(thousand) + " Thousand";
}
if (rest != 0) {
if (! result.isEmpty())
result += " ";
result += three(rest);
}
return result;
}
-
分析
- 分治的思想,将数字拆成3个一组,
- 三个一组中又分成首位和后两位
- 首位就是1-9+Hundred
- 后两位分成0-9 10-19 20-99
- 将数字拆成三个一组,得到每一组的表达,根据所在的位置在每一组的表达之后加上单位即可
-
提交结果
274. H 指数
给定一位研究者论文被引用次数的数组(被引用次数是非负整数)。编写一个方法,计算出研究者的 h 指数。
h 指数的定义:h 代表“高引用次数”(high citations),一名科研人员的 h 指数是指他(她)的 (N 篇论文中)总共有 h 篇论文分别被引用了至少 h 次。(其余的 N - h 篇论文每篇被引用次数 不超过 h 次。)
例如:某人的 h 指数是 20,这表示他已发表的论文中,每篇被引用了至少 20 次的论文总共有 20 篇。
- 解答
public int hIndex(int[] citations) {
Arrays.sort(citations);
int len = citations.length;
for(int i = 0;i < len;i++){
int number = Math.min(citations[i],len-i);
if(number == len-i)
return number;
}
return 0;
}
-
分析
- 将数组先排序
- 然后遍历数组,计算当前值与len-i中的较小者。例如0,1,7,8,9。遍历到第三位的时候是7,len-i是3,得到的结果就是3。
- 若b中得到的结果等于len-i 则就是要找的H指数
-
提交结果
275. H指数 II
给定一位研究者论文被引用次数的数组(被引用次数是非负整数),数组已经按照升序排列。编写一个方法,计算出研究者的 h 指数。
h 指数的定义: “h 代表“高引用次数”(high citations),一名科研人员的 h 指数是指他(她)的 (N 篇论文中)总共有 h 篇论文分别被引用了至少 h 次。(其余的 N - h 篇论文每篇被引用次数不多于 h 次。)"
- 解答
public int hIndex(int[] citations) {
int len = citations.length;
if(len == 0) return 0;
int left = 0;
int right = len-1;
while(left <= right){
int mid = (left+right)/2;
if(citations[mid] == len - mid)return len - mid;
if(citations[mid] < len - mid)left = mid + 1;
else right = mid - 1;
}
return len - left;
}
-
分析
- 二分查找来实现,可以减少搜索的时间复杂度
- mid所指向的值等于len-mid则是要找的H指数直接返回
- 否则当mid所指向的值小于len-mid,那么H指数必定在mid的右侧,所以left = mid+1
- 同理当mid所指向的值大于len-mid时,那么H指数必定在mid的左侧,所以right = mid-1
-
提交结果
278. 第一个错误的版本
你是产品经理,目前正在带领一个团队开发新的产品。不幸的是,你的产品的最新版本没有通过质量检测。由于每个版本都是基于之前的版本开发的,所以错误的版本之后的所有版本都是错的。
假设你有 n 个版本 [1, 2, …, n],你想找出导致之后所有版本出错的第一个错误的版本。
你可以通过调用 bool isBadVersion(version) 接口来判断版本号 version 是否在单元测试中出错。实现一个函数来查找第一个错误的版本。你应该尽量减少对调用 API 的次数。
- 解答
public class Solution extends VersionControl {
public int firstBadVersion(int n) {
int left = 1;
int right = n;
while(left <= right){
int mid = left + (right-left)/2;
if(isBadVersion(mid))right = mid-1;
else left = mid + 1;
}
return left;
}
}
-
分析
-
二分查找来实现
-
关键在于mid的计算,left + (right-left)/2;若使用(left+right)/2,会导致left+right计算的时候溢出,得到错误的mid结果。
-
-
提交结果
279. 完全平方数
给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, ...
)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。
- 解答
public int numSquares(int n) {
if(n<=3)return n;
int[] dp = new int[n + 1];
for (int i = 0; i < n + 1; i++) {
dp[i] = Integer.MAX_VALUE;
}
dp[0] = 0;
dp[1] = 1;
dp[2] = 2;
dp[3] = 3;
int[] sqares = new int[(int) Math.sqrt(n)];
for (int i = 0; i < sqares.length; i++) {
sqares[i] = (int) Math.pow(i + 1, 2);
}
for (int i = 4; i <= n; i++) {
for (int j = 0; j < sqares.length; j++) {
if (i - sqares[j] >= 0)
dp[i] = Math.min(dp[i - sqares[j]] + 1, dp[i]);
}
}
return dp[n];
}
//方法二
Set<Integer> square_nums = new HashSet<Integer>();
protected boolean is_divided_by(int n, int count) {
if (count == 1) {
return square_nums.contains(n);
}
for (Integer square : square_nums) {
if (is_divided_by(n - square, count - 1)) {
return true;
}
}
return false;
}
public int numSquares(int n) {
square_nums.clear();
for (int i = 1; i * i <= n; ++i) {
square_nums.add(i * i);
}
int count = 1;
for (; count <= n; ++count) {
if (is_divided_by(n, count))
return count;
}
return count;
}
//方法三
public int numSquares(int n) {
Set<Integer> squares = new HashSet<>();
for(int i = 1; i*i <= n;i++){
squares.add(i*i);
}
Set<Integer> queue = new HashSet<>();
queue.add(n);
int res = 0;
while(!queue.isEmpty()){
res++;
Set<Integer> nextQueue = new HashSet<>();
for(Integer remain:queue){
for(Integer square:squares){
if(remain - square == 0)return res;
if(remain -square < 0)continue;
nextQueue.add(remain - square);
}
}
queue = nextQueue;
}
return res;
}
-
分析
- 方法一使用动态规划实现,记录当前位置组成的完全平方数的最少个数。
- 寻找最少个数,就是当前位置的值,减去比他小的完全平方数的dp对应的数字+1.选择最小的一个作为这一位的结果。
- 最后返回dp数组最后一位即是答案。
- 方法二使用递归实现
- 次数从1开始遍历,在规定次数内能否由完全平方数组合而成。
- 方法三,当作树来处理,根结点是n,其孩子就是n减去比它小的完全平方数。再继续判断孩子的孩子,当某一个孩子是完全平方数的时候,这时候就找到了最少个数组合的结果。返回层数即可。
-
提交结果
方法一
方法二
方法三