算法虐我千百遍,我待算法仍如初恋(一)
hello,兄弟们!在经过这几天的专业学习后越来越发现自己的算法基础太差了,一些简单的的算法逻辑我都不会。不管前端还是后端都需要一定的算法基础,所以我决定了!我要手撕算法,有没有兄弟们要和我一起的,我们可以一起虐算法千百遍!!!
手刃算法第一式:两数之和
给定一个整数数组
nums
和一个整数目标值target
,请你在该数组中找出 和为目标值target
的那 两个 整数,并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。 你可以按任意顺序返回答案。
示例 1:
输入: nums = [2,7,11,15], target = 9
输出: [0,1]
解释: 因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
示例 2:
输入: nums = [3,2,4], target = 6
输出: [1,2]
示例 3:
输入: nums = [3,3], target = 6
输出: [0,1]
我的解答
当我拿到这个算法的第一印象就是利用暴力枚举法,两次循环判断两数之和是否等于目标target的值,然后将其存入数组输出出来。
我也这样做了,具体代码如下:
class Solution {
public int[] twoSum(int[] nums, int target) {
for(int i=0;i<nums.length;i++){
for(int j=i+1;j<nums.length;j++){
if(target==(nums[i]+nums[j])){
return new int[]{i,j};
}
}
}
return new int[0];
}
}
我信心满满的提交这个答案后,结果系统给我报错了,原来是因为第二个循环我把j++
写成了i++
这样系统就给我提示了一个数组越界异常。着实有点马虎了哈。不过我很快将这个问题改正过来了,提交后显示我打败了19%的java用户。
着实太菜了!!!
官方详解
因为还有一种更好的解题方法,就是利用hash表来解决,我认真的阅读了这个最优解,确实挺优秀的。hash表居然还可以干这种事,我学习了hash表啥都不会用。只知道是一种数据结构。
class Solution {
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> hashtable = new HashMap<Integer, Integer>();
for (int i = 0; i < nums.length; ++i) {
if (hashtable.containsKey(target - nums[i])) {
return new int[]{hashtable.get(target - nums[i]), i};
}
hashtable.put(nums[i], i);
}
return new int[0];
}
}
作者:力扣官方题解
这是我copy下来的,以我这脑子现在还写不出这样的代码。
不过经过我努力的读,我最终还是读懂了。建议像我一样的小菜鸡们先看看代码自己先读一下,大佬就不需要了。
现在我开始讲讲我读代码读出来的东西了哟,还没读代码的先不要往下翻了。
个人解读(如果有理解不对的地方大佬们看到了要不吝赐教哟)
这思路主要就是设置一个空哈希表来存储需要数组中的值及其所在的下标,设计一个值为target-nums[i]
即两个之和之中的另一个值,我就记为b
。循环给定的数组,如果哈希表中包含b,就返回由哈希表中的值及循环到的下标组成的新数组。否则的话就将循环到的数组的值及下标存储的哈希表中。
个人小小的思考
在读完这段代码后,我就在想能不能向hash表中添加数据和判断的顺序调换。这样看起来貌似没有错,但是实际上还是会存在一些问题。
[3,2,4]
6
在这一组测试数据中返回的是一个错误的数据,它会返回[1,1],违背了数组中同一个元素在答案里不能重复出现
这个规则。
另外是不是把两者调换一下会多一次添加的过程,浪费资源??有没有大佬可以给我解答一下疑惑??
手刃算法第二式:字母异位词分组
给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。
字母异位词 是由重新排列源单词的所有字母得到的一个新单词。
示例 1:
输入: strs = ["eat", "tea", "tan", "ate", "nat", "bat"]
输出: [["bat"],["nat","tan"],["ate","eat","tea"]]
示例 2:
输入: strs = [""]
输出: [[""]]
在看到这道题目的时候有点懵?这题目啥意思?咋都看不懂题目···
后来终于是看懂了。我第一想法就是现学现卖,拿到刚开始那道题学到的利用hash表来存储数据。
我的解答
首先要如何确定它们是一组字母异位分词
我们可以将这些单词转换为字符数组,然后通过字符数组的排序方法将其进行排序组成新的字符串,如果重排后的字符串是一样的,那么他们就是一组字母异位词。
该怎么分组存储字母异位词 我们将重排后的字符串作为hash表的键值存入哈希表,将所有重新排序后一样的字符串以其原值作为hash表的值集合的形式存入进去。
具体代码如下
class Solution {
public List<List<String>> groupAnagrams(String[] strs) {
Map<String, List<String>> map = new HashMap<>();
for (String s : strs) {
char[] chars = s.toCharArray();
Arrays.sort(chars);
String sortedStr = new String(chars);
// 如果map中已经有这个排序后的字符串作为键,则将当前字符串加入到对应的值列表中
if (!map.containsKey(sortedStr)) {
map.put(sortedStr, new ArrayList<>());
}
map.get(sortedStr).add(s);
}
// 返回所有的字母异位词分组合并后的列表
return new ArrayList<>(map.values());
}
}
这代码我写不了一点,不过这个思路是我自己想的,代码实现在这个hash表这一块还是有点缺陷,这里主要借助了通义千问
我的代码小助理 别喷我,我在努力学习中!争取早点能够能够实现手敲代码自由!
官方解答
class Solution {
public List<List<String>> groupAnagrams(String[] strs) {
Map<String, List<String>> map = new HashMap<String, List<String>>();
for (String str : strs) {
char[] array = str.toCharArray();
Arrays.sort(array);
String key = new String(array);
List<String> list = map.getOrDefault(key, new ArrayList<String>());
list.add(str);
map.put(key, list);
}
return new ArrayList<List<String>>(map.values());
}
}
作者:力扣官方题解
我的思路与这个解法思路大同小异,不过List<String> list = map.getOrDefault(key, new ArrayList<String>());
使用map的getOrDefault方法貌似要好一点。这个方法是在map中查找给定的key,如果找到了就返回key所关联的值,否则就返回一个默认的值new ArrayList<String>()
空数组。
这题还有第二种解法,不过看着代码挺长的,我没有去看。
如果感兴趣的小伙伴们,可以自己去看哦!!
算法怎么刷 ? leetcode.cn/studyplan/t…
如果有和我一样动手废物可以一起来刷刷题哟!我突然发现还可以用js做,以后看看能不能练练js,java实在是比不过啊!
转载自:https://juejin.cn/post/7372765277459300362