2018.12.25 leetcode 刷题总结
题号:949
给定一个由 4 位数字组成的数组,返回可以设置的符合 24 小时制的最大时间。
最小的 24 小时制时间是 00:00,而最大的是 23:59。从 00:00 (午夜)开始算起,过得越久,时间越大。
以长度为 5 的字符串返回答案。如果不能确定有效时间,则返回空字符串。
示例 1:
输入:[1,2,3,4]
输出:“23:41”
示例 2:
输入:[5,5,5,5]
输出:""
提示:
A.length == 4
0 <= A[i] <= 9
我的想法:
- 获得所有合法的小时组合,并记录它们在数组中的位置
- 遍历所有合法的小时数,获得相应小时数最大的合法的分钟数,即数组中去除组合成小时数的两个数去组成最大的合法的分钟数
- 在遍历的时候找出最大的合法的小时数+分钟数的组合
- 所有数字的不满足的结果或初始值都会被赋成 -1
对应程序:
// java
class Solution {
public String largestTimeFromDigits(int[] A) {
// 获得所有合法的小时组合
// hourMap<小时数,List<组成小时数的两个数字的下标>>
Map<Integer, List<Integer>> hourMap = hourCombo(A);
// 若不存在,返回空
if(hourMap.size() == 0) {
return "";
}
// 记录最大的小时数
int maxHour = -1;
// 记录同小时数相对应的分钟数
int maxMin = -1;
// 遍历所有合法的小时数
for(Integer hour : hourMap.keySet()) {
List<Integer> list = hourMap.get(hour);
// 获得与小时数相对应的分钟数
int minute = maxMinute(A, list);
// 若无合法的分钟数,跳到下一个小时数
if(minute == -1) {
continue;
}else {
// 找出最大的组合
// 注意,能进到这个else中说明小时+分钟的组合都是合法的,
// 因此,找出小时数最大的就是组合后时间最大的
if(hour > maxHour) {
maxHour = hour;
maxMin = minute;
}
}
}
// 若不存在,返回空
if(maxHour == -1 || maxMin == -1) {
return "";
}
// 转换格式,将一位数的数字前面加0
String hourStr = String.valueOf(maxHour);
if(maxHour < 10) {
hourStr = "0" + hourStr;
}
String minuteStr = String.valueOf(maxMin);
if(maxMin < 10) {
minuteStr = "0" + minuteStr;
}
// 返回 小时:分钟
return hourStr + ":" + minuteStr;
}
// 获得最大的合法的分钟数
// @param A:所给数组
// @param list:组成小时数的两个数的下标
private int maxMinute(int[] A, List<Integer> list) {
boolean flag = true;
int a = -1;
int b = -1;
// 拿到数组中其余两个数,分别赋给a,b
for(int i = 0 ;i < A.length; ++i) {
if(i == list.get(0) || i == list.get(1)) {
continue;
}
if(flag) {
a = A[i];
flag = false;
}else {
b = A[i];
}
}
// 得到所有的分钟数(2种)
int ab = a * 10 + b;
int ba = b * 10 + a;
// 找出在[0,59]中最大的一个数并返回,不存在返回-1
int result = -1;
if(ab >= 0 && ab <= 59) {
if(ab > result) {
result = ab;
}
}
if(ba >= 0 && ba <= 59) {
if(ba > result) {
result = ba;
}
}
return result;
}
// 获得所有合法的小时数的组合,并记录他们的下标位置
private Map<Integer, List<Integer>> hourCombo(int[] A) {
Map<Integer, List<Integer>> map = new HashMap<>();
List<Integer> list = null;
for(int i = 0; i < A.length; ++i) {
for(int j = 0; j < A.length; ++j) {
// 不能和自己做小时数
if(j == i) {
continue;
}
// 计算所有可能的小时数
int num = A[i] * 10 + A[j];
// 将小时数限制在[0,23]之间
if(num >= 0 && num <= 23) {
list = new ArrayList<>();
// 记录下标
list.add(i);
list.add(j);
// 添加结果
map.put(num, list);
}
}
}
return map;
}
}
题号:367
给定一个正整数 num,编写一个函数,如果 num 是一个完全平方数,则返回 True,否则返回 False。
说明:不要使用任何内置的库函数,如 sqrt。
示例 1:
输入:16
输出:True
示例 2:
输入:14
输出:False
我的想法:
n的完全平方等于n项由1开始的奇数的和
e.g. 16 = 1 + 3 + 5 + 7
对应程序:
// java
class Solution {
public boolean isPerfectSquare(int num) {
int flag = 1;
while(num > 0) {
num -= flag;
flag += 2;
if(num == 0) {
return true;
}
}
return false;
}
}
这个办法在所给数字非常大的时候会费时,提交记录中执行用时0ms的解答中用的是一种缩小区间逐渐逼近答案的办法,类似二分查找法
程序:
// java
class Solution {
public boolean isPerfectSquare(int num) {
long temp=num/2+1;
long start=0;
long end=temp;
while(start<=end){
long mid=start+(end-start)/2;
long result=mid*mid;
if(result==num)
return true;
else if(result<num)
start=mid+1;
else
end=mid-1;
}
return false;
}
}
上面的程序中,初始区间选在[0,n/2+1]之间,可以保证任何数的平方根都落在此区间,因为 (n/2+1)2 - n = n2/4 + 1 一定是大于零的。
题号:374
我们正在玩一个猜数字游戏。 游戏规则如下:
我从 1 到 n 选择一个数字。 你需要猜我选择了哪个数字。
每次你猜错了,我会告诉你这个数字是大了还是小了。
你调用一个预先定义好的接口 guess(int num),它会返回 3 个可能的结果(-1,1 或 0):
-1 : 我的数字比较小
1 : 我的数字比较大
0 : 恭喜!你猜对了
示例 :
输入: n = 10, pick = 6
输出: 6
我的想法:
二分查找,缩小查找区间,递归调用guess()函数
对应程序:
// java
/* The guess API is defined in the parent class GuessGame.
@param num, your guess
@return -1 if my number is lower, 1 if my number is higher, otherwise return 0
int guess(int num); */
public class Solution extends GuessGame {
public int guessNumber(int n) {
return guessNumber(1, n);
}
// @param start:区间左端点
// @param end: 区间右端点
private int guessNumber(int start, int end) {
// 二分查找,标志位数字
// 不要直接写成(start + end)/ 2,防止溢出
int temp = start + (end - start)/2;
// 得到查询结果标志
int guessFlag = guess(temp);
if(guessFlag == 0) {
// 递归出口
return temp;
}else if(guessFlag < 0) {
// 区间向左缩小
return guessNumber(start, temp-1);
}else {
// 区间向右缩小
return guessNumber(temp+1, end);
}
}
}