2019.1.4 leetcode 刷题总结
题号:169
给定一个大小为 n 的数组,找到其中的众数。众数是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。
你可以假设数组是非空的,并且给定的数组总是存在众数。
示例 1:
输入: [3,2,3]
输出: 3
示例 2:
输入: [2,2,1,1,1,2,2]
输出: 2
我的想法:
- 用Map记录每个数字在数组中出现的次数,即Map<数字,出现次数>
- 遍历Map,找出那个数字出现次数多于数组长度一半的数字,并返回
应对程序:
// java
class Solution {
public int majorityElement(int[] nums) {
Map<Integer, Integer> map = new HashMap<>();
for(int num : nums) {
int value = 1;
if(map.containsKey(num)){
value = map.get(num);
// 若map中存在该值,出现次数加一
value++;
}
map.put(num, value);
}
int max = 0;
int result = Integer.MIN_VALUE;
for(int num : map.keySet()){
int val = map.get(num);
if(val > nums.length/2 && val > max){
max = val;
result = num;
}
}
return result;
}
}
优化:
以上代码虽然可以解决问题,但执行效率过低,去网上搜,发现了摩尔投票法:在一组数中,假定第一个数是众数,向后比较,若相同,计数器+1;若不相同,计数器-1,当计数器为0时,用当前数字替代当前众数,重复以上操作,直到遍历结束,当前众数即为所求。
程序:
// java
class Solution {
public int majorityElement(int[] nums) {
int flag = 0;
int n = 0;
for(int num : nums) {
if(n == 0) {
flag = num;
}
if(flag == num) {
n++;
}else {
n--;
}
}
return flag;
}
}
再看其他人的提交记录,发现一种更简洁的算法:将给定数组排顺序后,返回数组中间的那个值即为众数。
程序:
// java
class Solution {
public int majorityElement(int[] nums) {
Arrays.sort(nums);
return nums[nums.length/2];
}
}
该问题的关键在于众数是一定存在的,又众数的特点是出现次数超过一半,因此,只要抓住这两点解题便会容易许多。
题号:258
给定一个非负整数 num,反复将各个位上的数字相加,直到结果为一位数。
示例:
输入: 38
输出: 2
解释: 各位相加的过程为:3 + 8 = 11, 1 + 1 = 2。 由于 2 是一位数,所以返回 2。
进阶:
你可以不使用循环或者递归,且在 O(1) 时间复杂度内解决这个问题吗?
我的想法:
各位相加,递归,直到结果小于10为止
对应程序:
// java
class Solution {
public int addDigits(int num) {
int temp = 0;
for(char c : String.valueOf(num).toCharArray()) {
temp += (c - 48);
}
if(temp >= 10) {
return addDigits(temp);
}
return temp;
}
}
优化:
题目中说不用递归,不用循环如何求解,那么就一定存在公式,我所想到的,以一个两位数为例,可以表示成10a+b,各位相加的结果是a+b,因此原数和各位相加的结果差了一个9a;因此只要将原数字不停的减掉9倍的最高位数字,当结果是一位数时,即为所求。
其实这是一个数字根的问题,用到了同余定理,大家可以看看这篇文章LeetCode笔记-----各位相加
题号:728
自除数 是指可以被它包含的每一位数除尽的数。
例如,128 是一个自除数,因为 128 % 1 == 0,128 % 2 == 0,128 % 8 == 0。
还有,自除数不允许包含 0 。
给定上边界和下边界数字,输出一个列表,列表的元素是边界(含边界)内所有的自除数。
示例 1:
输入:
上边界left = 1, 下边界right = 22
输出: [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 15, 22]
我的想法:
- 遍历所有给定的边界之间的数,判断数字是否符合自除数,若符合,在结果集中添加
- 判断每个数字是否是自除数,先获得当前数字的每位上的数字,用当前数字和每位上的数字取余,若为零,继续,若不为零,去判断下一个数字
对应程序:
// java
class Solution {
public List<Integer> selfDividingNumbers(int left, int right) {
List<Integer> res = new ArrayList<>();
for(int temp = left; temp <= right; ++temp) {
if(isSDNum(temp, getAll(temp))) {
res.add(temp);
}
}
return res;
}
/**
* 判断当前数字是否为自除数
* @param: num:当前数字
* @param: list:当前数字个位置上的数字集合
*/
private boolean isSDNum(final int num, List<Integer> list) {
for(int n : list) {
// 0不能做除数
if(n == 0) {
return false;
}
// 不可被整除
if(num % n != 0) {
return false;
}
}
return true;
}
/**
* 获得当前数字每位上的数字
* @param: num:当前数字
*/
private List<Integer> getAll(int num) {
List<Integer> res = new ArrayList<>();
int o = num;
while(o != 0) {
o = num / 10;
res.add(num % 10);
num = o;
}
return res;
}
}
优化:
可以在拿到每位上的数字的同时做判断
程序:
// java
// 修改isSDNum()方法,去除getAll()方法
private boolean isSDNum(final int num) {
// n表示商
int n = num;
while(n != 0) {
// y表示余数,即每位上的数字
int y = n % 10;
if(y == 0) {
return false;
}
if(num % y != 0) {
return false;
}
n /= 10;
}
return true;
}
题号:389
给定两个字符串 s 和 t,它们只包含小写字母。
字符串 t 由字符串 s 随机重排,然后在随机位置添加一个字母。
请找出在 t 中被添加的字母。
示例:
输入:
s = “abcd”
t = “abcde”
输出:
e
解释:
‘e’ 是那个被添加的字母
我的想法:
将两个字符串的每个字符分别存入List中,用List.removeAll(AnotherList)方法取差集,再写完代码后发现是错误的,因为List.removeAll(AnotherList)方法是基于判断List中是否含有AnotherList中的元素,而不考虑该元素的数量,因此在s=“a”,t="aa"这样的测试用例时就会出现问题。
想到之前的题(题号268),因此想到这样一种解决办法:将所给字符串转换为字符数组,计算这个数组的int和,作差,再转回char,返回
对应程序:
// java
class Solution {
public char findTheDifference(String s, String t) {
int sSum = getValue(s);
int tSum = getValue(t);
return (char)(tSum - sSum);
}
// 计算字符串对应的字符数组的和
private int getValue(String str) {
int res = 0;
for(char c : str.toCharArray()) {
res += c;
}
return res;
}
}
3ms,击败100%