leetcode刷题记录(169、258、728、389)

2019.1.4 leetcode 刷题总结

题号:169

给定一个大小为 n 的数组,找到其中的众数。众数是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。
你可以假设数组是非空的,并且给定的数组总是存在众数。

示例 1:
输入: [3,2,3]
输出: 3
示例 2:
输入: [2,2,1,1,1,2,2]
输出: 2

我的想法:

  1. 用Map记录每个数字在数组中出现的次数,即Map<数字,出现次数>
  2. 遍历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]

我的想法:

  1. 遍历所有给定的边界之间的数,判断数字是否符合自除数,若符合,在结果集中添加
  2. 判断每个数字是否是自除数,先获得当前数字的每位上的数字,用当前数字和每位上的数字取余,若为零,继续,若不为零,去判断下一个数字

对应程序:

// 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%

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值