重回代码之我是谁
很久没打代码了,重新回到LeetCode练练手,然后满心充斥着几个问题:我是谁?我在哪?我要干什么?
不知道各位是否有这种感觉,很久不熟练代码之后,尽管你的思路还挺清晰,但是你会发现遗忘了很多基础问题,比如说各种集合…所以说现在开端想给我自己同时也给大家一个告诫:“不可一日不打代码”AND“开发大道就像逆水行舟,不进则退”
重生LeetCode之第一题也能关我?
在重新做第一题之前,我是没想到曾经秒秒钟解决的我会卡了这么久…各种基础知识的遗忘以及错误的操作规范,让我在这卡的怀疑人生…以下是这道题的相关内容:
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那两个整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
示例 1:
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
示例 2:
输入:nums = [3,2,4], target = 6
输出:[1,2]
示例 3:
输入:nums = [3,3], target = 6
输出:[0,1]
这道题我看到的第一时间想到的是用一个循环(不知道怎么回事脑抽了),然后在循环里对 i 进行+1,结果发现效率奇低(能不能实现不确定,我弄到一半就换成双循环了)。然后很尴尬的事情发生在了写双循环的过程中。
双循环中发现自己就是个弱鸡
在最开始写双循环的过程中,我甚至忘记了基本规则——变量的适用范围。这里就不详细说明了,基本上刚开始学过的都多少遇到过这种问题。(说的自己跟个萌新一样…私密马赛…)在经过了长达半个多小时的艰难编程之后,第一版终于写出来了。
class Solution {
public static int[] twoSum(int[] nums, int target) {
int start;
int first;
int second;
int result;
int[] results = new int[2];
for(start=0;start<nums.length;start++){
//从前往后遍历,每个start都是first
first = nums[start];// 数组中依次的第一个数
second = target - first;//不同的第一个数相对应的第二个数
for(int i = 1; start + i < nums.length ; i++ ){
if(nums[start + i] == second){
results[0] = start ;
results[1] = start + i;
}
}
}
return results;
}
}
可能很多萌新第一眼还看不出什么问题,但对比一下下一版就知道了。
class Solution {
public static int[] twoSum(int[] nums, int target) {
int start;
int first;
int second;
int result;
int[] results = new int[2];
for(int i =0 ; i<nums.length;++i){
for(int j = i + 1; j < nums.length ; ++j ){
if(nums[i] + nums[j] == target){
results[0] = i ;
results[1] = j;
}
}
}
return results;
}
}
可以很明显的看出少了很多多余的赋值。可能在这种小的实现中看不出什么大的差异,但是业务繁重以后这些都是可以优化的点。然后在看了别人的回答以后,进一步优化出了第三版,也就是双循环的最终版。
class Solution {
public static int[] twoSum(int[] nums, int target) {
for(int i =0 ; i<nums.length;++i){
for(int j = i + 1; j < nums.length ; ++j ){
if(nums[i] + nums[j] == target){
return new int[]{i,j};
}
}
}
return new int[0];
}
}
这个是不是更明显了…比之前少了很多变量,然后对于数组的赋值也是直接在创建的时候加入了进去,效果不好说,但是从整个代码的整洁度和可读性方面来说,有了很大的提升。但是这三种改进其实没有根本性的优化,我觉得更多的来说还是增加了整洁性和可读性,效率没有什么变化。如下图:
看答案解析发现的意料之外情理之中的答案
话不多说,先上代码:
class Solution {
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> hash = new HashMap<Integer, Integer>();
for (int i = 0; i < nums.length; ++i) {
if (hash.containsKey(target - nums[i])) {
return new int[]{hash.get(target - nums[i]), i};
}
hash.put(nums[i], i);
}
return new int[0];
}
}
好家伙,看完才恍然大悟————Bee————Map的K-V键值对居然被我遗忘了…只能说上Map之后这代码看起来才有了些味道。(简洁流畅效率高的代码才是我们的毕生追求!)每一个K值 i 遍历寻找他对应的V值 target - nums[i]
,如果找到了返回True,否则返回False。ContainsKey:如果 hashMap 中存在指定的 key 对应的映射关系返回 true,否则返回 false。
最后根据结果,用get获取键k的值,即对应的序号。同时为了防止与自己匹配, 将遍历过的值put到Hashmap中。以下,是对应的效率:
只能说,这就是差距吧…
总结
总之这次重刷题发现很多东西掌握的确实不牢固,还有待加强,多努力,多记,多刷题,争取早日变成大牛!题海战术在某方面来说可是相当有用的,干巴爹!