为自己加更!明天周末,为了能放下心玩一天,今天要额外刷三道题!
Excel表列名称
题目:给定一个正整数,返回它在 Excel 表中相对应的列名称。例如,
1 -> A
2 -> B
3 -> C
...
26 -> Z
27 -> AA
28 -> AB
...
示例 1:
输入: 1
输出: "A"
示例 2:
输入: 28
输出: "AB"
示例 3:
输入: 701
输出: "ZY"
怎么说呢,这道题属于解是肯定能解出来,就是优雅不优雅的问题。我发现现在做题真的如果不考虑代码的性能之类的问题,单纯求解还是很简单的。闲话少叙,说思路:我觉得这道题就是很单纯的找规律的问题。现在去仔细看看规律,一会儿回来再说
大行打脸现场再次出现,这道题,我做了一个多小时,没做出来。对,我才说过很简单的,结果卡壳了。重新理一下思路。这可以看作是一个26进制的问题。然后A代表1,B代表2,Z代表26。但是有个问题,就是遇到26的倍数,是不进位的,而只是AZ,BZ这样表示。这就很烦躁。说26进制不26,说27进制也莫得27。我一直就是卡在这里了,递归,while循环,for循环都判断了。不行。除非判断是不是一个被26整除的数。如果是则怎么怎么样。这样还涉及到一个多位问题。之前看题目我以为只是1-702之间呢,结果一提交发现可以好多位,然后推翻重写。最后决定把这个特殊情况提出来单独判断。结果判断来判断去把自己判断蒙了,所以决定出绝招:看大佬思路!
大佬思路很简单,说26进制就是26进制。Z不听话怎么办?盘它呗!不开玩笑了,就是完全把A-Z的意义改变。A表示0.B表示1.C表示2....Z表示25.这样就是一个很成熟的26进制了。如果理解不了可以想想10进制,从0开始到9。10这个数字是没有的!
然后既然26进制完善了,接下来完全可以按照进制的方法来做了。不过要注意一点,实际上代表的数字比咱们进制代表的数值是大1的(回忆一下,题目中A是1.B是2,,,Z是26).所以在每一步用进制换算的时候是要把这个1减去的。只要这个能明白,这个题做起来真三行代码。
上代码:
class Solution {
public String convertToTitle(int n) {
StringBuilder sb = new StringBuilder();
while(n>0){
//注意这个一定要先-1再取余数,不然先取余再-1会出现莫名其妙的问题。比如都取余0了,再减1.不用我说了吧?
n--;
//这里是个巧妙的算法。数字加上字符'A'.再转化成char。
//'A'本来就是数字,'B'比'A'大1。如果是1+'A'结果转成char就是'B'。以此类推。很容易理解。
sb.append((char)(n%26+'A'));
n=n/26;
}
return sb.reverse().toString();
}
}
再一次对思路感觉惊奇,日常一叹吧。真的有时候就差那么一个思路。有了,豁然开朗。没有怎么也想不出来。然后再次感谢leetCode里提供思路的大佬,好人一生平安吧~继续下一题。
多数元素
给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。你可以假设数组是非空的,并且给定的数组总是存在多数元素。
示例 1:
输入: [3,2,3]
输出: 3
示例 2:
输入: [2,2,1,1,1,2,2]
输出: 2
思路:一点也不夸张的说,不考虑性能问题分分钟做出这道题(我要找回上道题被打的脸)!但是说一点不考虑性能就有点过分了。反正我一下好几个思路。比如存map,值是key,次数是val,累加的。什么时候某个val大于n/2说明那个就是多数元素。还有把数组转成list然后排序。因为确定多数肯定一半以上。直接获取中间的元素看是什么那么多数元素就是什么。然后我要去撸代码测性能啦!
回来了,用我简单粗暴的方法做完了,性能比我想得好得多:
class Solution {
public int majorityElement(int[] nums) {
Map<Integer,Integer> map = new HashMap<Integer,Integer>();
for(int i:nums){
if(map.containsKey(i)){
if(map.get(i)+1>=nums.length/2+1){
return i;
}else{
map.put(i,map.get(i)+1);
}
}else{
map.put(i,1);
}
}
//在只要一个元素的情况下会直接走到这
return nums[0];
}
}
第二种想法也写出来了:
class Solution {
public int majorityElement(int[] nums) {
//转化成集合
List<Integer> list = Arrays.stream(nums).boxed().collect(Collectors.toList());
//排序
Collections.sort(list);
//返回中间位数的元素
return list.get(list.size()/2);
}
}
然后两种方法速度都很感人。我要想想怎么优化了。
另外一个小题外话:原来Leetcode是用jdk8运行的。因为我用java 9的方法报错没有这个方法。就是下面这个List.of();
好了,题外话说完了,我要开始研究这个题的最优性能的解了:
我要郑重认个错!!我发现数组能直接排序的,所以我上个方法中先转list再排序纯粹因为知识面窄,会的方法少。
class Solution {
public int majorityElement(int[] nums) {
Arrays.sort(nums);
//返回中间位数的元素
return nums[nums.length/2];
}
}
这个是排序取中位数的解。虽然我还没看解析,但是我大概猜测这道题可能是想考数组的快排之类的?因为我现在直接数组排序取中位数运行速度是3ms,想要时间更短我觉得应该就是不要用现成的api?好了,墨迹完毕,我去看解析了。
你看我就猜到了,直接用api肯定是不被推荐的,哎,还好我还有一个map计数法。顺便我又顺着大佬的思路解答了一次:
从第一个数开始count=1,遇到相同的就加1,遇到不同的就减1,减到0就重新换个数开始计数,总能找到最多的那个,下面是代码:
class Solution {
public int majorityElement(int[] nums) {
int result = nums[0];
int count = 0;
for(int i : nums){
if(i==result || count==0){
result =i;
count++;
}else{
count--;
}
}
return result;
}
}
Excel表序列号
题目:给定一个Excel表格中的列名称,返回其相应的列序号。例如,
A -> 1
B -> 2
C -> 3
...
Z -> 26
AA -> 27
AB -> 28
...
示例 1:
输入: "A"
输出: 1
示例 2:
输入: "AB"
输出: 28
示例 3:
输入: "ZY"
输出: 701
思路:这个题怎么说呢。撩个狠话吧,今天做不出来我就转行!跟第一个题是一样的。只不过第一题是十进制转化二十六进制,这个题是二十六进制转化成10进制。傻瓜式还原操作。我去直接撸代码了。
做完回来了,半小时左右完成的,性能不好也不坏,反正能对付用。感觉这两道题做完对进制有了一个新的理解了。
其实只要上面第一题会了这个题就是一个逆推的过程。然偶就这样吧。
class Solution {
public int titleToNumber(String s) {
//结果
int result = 0;
//用来存每一个位数的十进制数字。
int n = 0;
for(int i =0;i<s.length();i++){
//因为26进制是0-25.而实际上是1-26.所以这里要+1.减去'A'的技巧就不多说了。
n = s.charAt(i)-'A'+1;
//这个是每个数位上的数 乘 26(数位次方-1).Math.pow(m,n)结果是m的n次方。
//理解不了就替换成十进制想
result += n * Math.pow(26,s.length()-1-i);
}
return result;
}
}
因为这个性能还不是最优我还是去看看大神的思路。
哎,人生啊~就是一个不断受打击再站起来的过程。
我以为的不好不坏,其实就是对付而已。大神思路:
public int titleToNumber(String s) {
int result = 0;
for(int i =0;i<s.length();i++){
result = result*26 + s.charAt(i)-'A'+1;
}
return result;
}
准确来讲算上括号五号代码。只能自然不如。
今天就到这了,顺便回忆回忆最近刷了四十多题,虽说都是算法题但是也对一些基础的api有了很大的了解和重新认识,同时对思路的扩展也有一定的作用(虽然离大神还远)。如果写的这些笔记或者说我自己思路的记录稍微帮到了你,记得点个喜欢点个关注呦!顺便祝大家也工作顺顺利利!周末愉快!