1.Algorithm:每周至少做一个 leetcode 的算法题
2.Review:阅读并点评至少一篇英文技术文章
3.Tip:学习至少一个技术技巧
4.Share:分享一篇有观点和思考的技术文章
###1.Algorithm:
这周完成了2条算法题和一条数据库题记录一下。
1.给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个-
整数,并返回他们的数组下标。你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。-
示例:给定 nums = [2, 7, 11, 15], target = 9因为 nums[0] + nums[1] = 2 + 7 = 9-
所以返回 [0, 1].
复制代码
方法一:两次遍历数组判断取值是否等于target。第一反应。
public static int[] twoSum(int[] nums, int target) {
int a[] = new int[2 * nums.length - 1];
int ind = 0;
for (int i = 0; i < nums.length - 1; i++) {
for (int j = i + 1; j < nums.length; j++) {
int sum = nums[i] + nums[j];
if (sum == target) {
int newa[] = new int[ind + 2];
System.arraycopy(a, 0, newa, 0, ind);
newa[ind] = i;
newa[ind + 1] = j;
ind += 2;
a = newa;
}
}
}
return a;
}
复制代码
我加了一点 返回所有不重复的两个整数的下标。
提交执行120ms ,分析了一下 时间复杂度:O(n^2),空间复杂度O(1)。
方法二:看了提示 两遍hash表
在第一次迭代中,将每个元素的值和它的索引添加到map中。--然后,在第二次迭代中,我们将检查每个元素所对应的目标元素( target−nums[i]target - nums[i] target−nums[i])是否存在于map中。
Map<Integer, Integer> map = new HashMap<>();
int a[] = new int[2 * nums.length - 1];
int ind = 0;
for (int i = 0; i < nums.length; i++) {
map.put(nums[i], i);
}
for (int i = 0; i < nums.length; i++) {
int complement = target - nums[i];
if (map.containsKey(complement) && map.get(complement) > i) {
int newa[] = new int[ind + 2];
System.arraycopy(a, 0, newa, 0, ind);
newa[ind] = i;
newa[ind + 1] = map.get(complement);
ind += 2;
a = newa;
}
}
return a;
复制代码
时间复杂度:O(n),空间复杂度O(n)。
方法三: 一遍hash表 在进行迭代并将元素插入到表中的同时,我们还会回过头来检查表中是否已经存在当前元素所对应的目标元素。如果它存在,那我们已经找到了对应解,并立即将其返回。
Map<Integer, Integer> map = new HashMap<>();
int a[] = new int[2 * nums.length - 1];
int ind = 0;
for (int i = 0; i < nums.length; i++) {
int complement = target - nums[i];
if (map.containsKey(complement)) {
int newa[] = new int[ind + 2];
System.arraycopy(a, 0, newa, 0, ind);
newa[ind] = map.get(complement);
newa[ind + 1] = i;
ind += 2;
a = newa;
}
map.put(nums[i], i);
}
return a;
复制代码
时间复杂度:O(n),空间复杂度O(n)。
总结:学过时间复杂度,空间复杂度,写代码是却总没有考虑过这些,如果遇到多层迭代 可考虑放入hash表中可降低时间复杂度和代码可读性。
2. 给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序--
的方式存储的,并且它们的每个节点只能存储 一位 数字。
如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
您可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例:
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807
复制代码
思路:当两个单链表 中有一个节点不为空时迭代两个节点,如果其中一个节点为null时将其new出来。然后求和当两个节点的值和大于10是取余数如果下一个节点为空之就new 一个节点值为1,否则就下一个节点值加1。
ListNode tempNode=new ListNode(0);
ListNode newNode=tempNode;
while (l1!=null || l2!=null) {
if(l1==null) {
l1=new ListNode(0);
}
if(l2==null) {
l2=new ListNode(0);
}
int temp=l1.val+l2.val;
int cur=temp/10;
int sum=cur==0?(l1.val+l2.val):(l1.val+l2.val-10);
newNode.next=new ListNode(sum);
newNode=newNode.next;
if (cur>0&& l1.next==null) {
l1.next=new ListNode(cur);
}else if(cur>0&& l1.next!=null){
l1.next.val+=1;
}
l1=l1.next;
l2=l2.next;
}
return tempNode.next;
复制代码
总结:单链表和双链表有点像看一下LinkList 源码。没题目解析说的好,附个[链接]leetcode-cn.com/problems/ad…
- leetcode 第 175. 组合两个表 leetcode-cn.com/problems/co…
总结:很简单 左连接以左边表为准。一样的代码为什么执行时间差别这么大。
###2.Review:
medium.freecodecamp.org/learn-to-co…
这篇文章讲述了如何学习Java 以及为什么学从哪里开始学习
首先简述了新人选择一门语言是非常重要的,然后简述了Java的优势。并且有全球最大的社区和高质量的文档来帮助学习。有很多的工具类和框架帮助开发,每六个月跟新一次,站在行业领先地位。然后讲述了Java学习需要很多时间,资源文件是否真实,如何避免犯错。等
然后再说了普遍的几种学习问题:
1.不设定具体目标的学习
2.没有实践的研究和理论太多...
复制代码
提供了一些学习建议:
1.学会独立编码
2.确保有一天你会完全理解编程的所有方面
3.制定一个完美的培训计划
4.制定教育计划。
5.选择正确的工具并加入编程社区。
复制代码
也提供了一些学习网站,博客社区等如何学习... 还好没忘太多,基本看得懂。
###3.Tip:
看了每条题目后面都有时间复杂度,空间复杂度的分析,就找了一篇复习了一下,记录一下。
好的算法应该具备时效高和存储低的特点。时效是指时间效率,也就是算法的执行时间,对于同一个问题的多种不同解决算法,执行时间越短的算法效率越高,越长的效率越低;存储是指算法在执行的时候需要的存储空间,主要是指算法程序运行的时候所占用的内存空间。
时间复杂度:
1. 用执行时间作为独立于具体程序或计算机的度量指标去描述一个算法的时候,确定这个算法所需要的步骤数目非常重要。
2. 当数据的规模越来越大时,T(n) 函数中的某一部分掩盖了其它部分对函数的影响
3.「数量级」函数用来描述当规模 n 增加时,T(n) 函数中增长最快的部分,这个数量级函数我们一般用「大 O」表示,记做 O(f(n))。
4.O(1) < O(logn) < O(n) < O(nlogn) < O(n^2) < O(n^3) < O(2^n)
复制代码
空间复杂度:
1.一个算法的空间复杂度是指该算法所耗费的存储空间,计算公式计作:S(n) = O(f(n))。其中 n 也为数据的规模,f(n) 在这里指的是 n 所占存储空间的函数。
2. 如果输入数据所占空间和算法无关,只取决于问题本身,那么只需要分析算法在实现过程中所占的「辅助单元」即可。如果所需的辅助单元是个常数,那么空间复杂度就是 O(1)。
复制代码
###4.Share:
分享一个回溯算法。blog.csdn.net/weiyuefei/a…
溯法按深度优先策略搜索问题的解空间树。首先从根节点出发搜索解空间树,当算法搜索至解空间树的某一节点时,先利用剪枝函数判断该节点是否可行(即能得到问题的解)。如果不可行,则跳过对该节点为根的子树的搜索,逐层向其祖先节点回溯;否则,进入该子树,继续按深度优先策略搜索。
回溯法的基本行为是搜索,搜索过程使用剪枝函数来为了避免无效的搜索。剪枝函数包括两类:
1. 使用约束函数,剪去不满足约束条件的路径;
2.使用限界函数,剪去不能得到最优解的路径。
问题的关键在于如何定义问题的解空间,转化成树(即解空间树)。解空间树分为两种:子集树和排列树。两种在算法结构和思路上大体相同。
复制代码
分享一个从源码mybatis一次查询经历了什么 juejin.im/post/5c99f9…