首先我在这里先介绍下算法对于我们个人的意义。在实际项目中,算法的使用场景有很多,如“Java8中Hashmap使用红黑树来实现”、“
Redis底层使用LRU来进做淘汰策略”、“大数据领域很多问题都基于TopK”、“JS原型链里使了类似链表的成环检测”、“特别复杂的业务逻辑经常涉及到DAG
”、“MySql为什么索引要用B+树”、“Oracle里的开窗函数如何实现” 等等等等。总之,
正是因为算法题目中只保留了必备的要素,舍弃了其他无关紧要的部分,所以可以对每一位做题人都构建一个学习解决问题的最佳环境
,而在这个环境中的成长与提高,将对一个软件工程师的生涯产生深远影响,乃至一世。所以,请大家能有一颗匠心,
你可以选择不去了解学习掌握算法,但是请不要耽误他人进步。山高水长,江湖路远,珍重万千,有缘再见!
<>一、LeetCode 350题 求两个集合中的差值
<>1.1 题目分析
我们先来看一道题目: 第350题:两个数组的交集
需求:给定两个数组,编写一个函数来计算它们的交集。
实例代码
输入: nums1 = [1,2,2,1], nums2 = [2,2] 输出: [2,2] 输入: nums1 = [4,9,5], nums2 = [9,
4,9,8,4] 输出: [4,9]
根据实例代码分析:
* 输出的结果应该与给定的两个集合共同出现的次数是相同的。
* 我们这里不考了排序的问题
* 首先拿着这个题目的时候,我们首先应该想到使用map的方式进行映射
,为什么可以这样看那,因为我们需要找出两个数组中交集的元素,同时应与两个数组中出现的次数一直,这样导致我们需要制每个值串的次数,所以映射关系就成了<元素,元素出现的次数>
<>1.2 题目讲解
根据分析,假设我们有两个数组分别为; nums1=[1,2,2,2] , nums2=[2,2]
首先我们定义一个map用来存其中一个数组中的数据,进行循环向数组中输入数据
第一次map中没有这个元素所以value为1
第二、三次map中如有这个元素value+1后面依次类推,就像使用map计算wordCount
首先我们需要进行判断map中是否这个数据,如果有则进行相加(后面的逻辑就是一样的了)
第二阶段
首先定义一个空的数组。我们现在获取到了map之后,map中就存储了我们每个元素及他们出现的个数,接下来我们在遍历nums2这个数组,拿着每个元素去map中get数据如果get到了数据value次数减1,将这个key复制给空的数组。
<>1.3 代码分析
public static int[] intersect(int[] nums1, int[] nums2) { // 判空操作 if (nums1 ==
null|| nums1.length == 0 || nums2 == null || nums2.length == 0) { return new int
[0]; } //1.定义一个map用来存储一个数组中的出现的值 value存储出现的个数 HashMap<Integer, Integer> map =
new HashMap<>(); for (int i = 0; i < nums1.length; i++) { Integer integer = map.
get(nums1[i]); if (integer == null) { map.put(nums1[i], 1); } else { map.put(
nums1[i], integer + 1); } } int k = 0; for (int i = 0; i < nums2.length; i++) {
Integer integer= map.get(nums2[i]); if (integer != null) { if (integer > 0) {
nums2[k] = nums2[i]; map.put(nums2[i], integer - 1); k++; } } } return Arrays.
copyOfRange(nums2, 0, k); }
<>1.4 题目进阶(优化)
前提:我们首先我们需要将两个数组进行排序
如果给定的数组已经排好序呢?你将如何优化你的算法?我们分析一下,假如两个数组都是有序的,分别为: nums1=[1,2,2,2] , nums2=[2,2]
解题步骤:
<1>如果两个指针的元素不相同,我们将小的指针往后一然后在进行判断
<2>如果两个元素相同,则两个指针同时后移
<3> 直到任意一个数组终止。
<>1.5 代码分析
public static int[] intersect2(int[] nums1, int[] nums2) { if (nums1 == null ||
nums1.length == 0 || nums2 == null || nums2.length == 0) { return new int[0]; }
int i = 0, j = 0, k = 0; Arrays.sort(nums1); Arrays.sort(nums2); while (i <
nums1.length && j < nums2.length) { if (nums1[i] > nums2[j]) { j++; } else if (
nums1[i] < nums2[j]) { i++; } else { nums2[k] = nums1[i]; i++; j++; k++; } }
return Arrays.copyOfRange(nums2, 0, k); }
<>二、LeetCode 14 最长公共前缀
<>2.1 题目分析
我们先来看一道题目: 第14: 最长公共前缀
需求:编写一个函数来查找字符串数组中的最长公共前缀。如果不存在公共前缀,则返回""
实例代码
输入: ["flower","flow","flight"] 输出: "fl" 输入: ["dog","racecar","car"] 输出: ""
题目分析:
我们要想寻找最长的公共前缀,那么首先这个前缀是公共的,我们可以从任意一个元素中找到他。假定我们现在就从一个数组中寻找最长公共前缀,那么首先,我们可以将第一个元素设置为基准元素x0。假如数组为[“flow”,“flower”,“flight”],flow就是我们的基准元素x0。
然后我们只需要依次将基准元素和后面的元素进行比较(假定后面的元素依次为x1,x2,x3…),
不断更新基准元素,直到基准元素和所有元素都满足最长公共前缀的条件,就可以得到最长公共前缀。
对比流程:
* 如果strs[i].indexOf(x0,x) ==
0,则直接跳过(因为此时x就是x1的最长公共前缀),对比下一个元素。(如flower和flow进行比较)
* 如果strs[i].indexOf(x0,x) != 0,
则截取掉基准元素x的最后一个元素,再次和x1进行比较,直至满足strs[i].indexOf(x0,x) ==
0,此时截取后的x为x和x1的最长公共前缀。(如flight和flow进行比较,依次截取出flow-flo-fl,直到fl被截取出,此时fl为flight和flow的最长公共前缀)
<>2.2 图解分析
<>2.3 代码分析
public static String longestCommonPrefix(String[] strs) { if (strs.length==0 ||
strs[0].length()==0){ return ""; } String mondel = strs[0].substring(0, strs[0]
.length() - 1); for (int i = 0; i < strs.length; i++) { if (mondel.length()==0){
return ""; } if (strs[i].indexOf(mondel)!=0){ while (true){ mondel=mondel.
substring(0,mondel.length()-1); if (mondel.length()==0){ break; } if (strs[i].
indexOf(mondel)==0){ break; } } } } return mondel==null? "":mondel; }
<>三、LeetCode 买卖股票的最佳时机(I、II)
面试时出现的频率非常的高。稍微改一改条件,就让我们防不胜防。那我们如何攻克这一类的问题那?我们从最贱的一道开始看起。
<>3.1 121题 买卖股票的最佳时机 I
<>3.1.1 题目分析
我们先来看一道题目: 第121题:买卖股票的最佳时机 I
需求:给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
如果你最多只允许完成一笔交易(即买入和卖出一支股票一次),设计一个算法来计算你所能获取的最大利润。
注意:你不能在买入股票前卖出股票。
示例1:
输入: [7,1,5,3,6,4] 输出: 5
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意:注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。
示例 2:
输入: [7,6,4,3,1] 输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
<>3.2.2 图解分析
假设我们是第二天买入,在收益在多的那一天卖出
执行流程
第二次执行
第三次执行… 以此类推,当我们整个循环遍历完成后maxV就获取到了整个数组中的最大收益。
<>3.1.3 代码分析
public static int maxProfit(int[] prices) { int maxProfit = 0, fi = 0, maxV = 0
; for (int i = 1; i < prices.length; i++) { fi = Math.max(maxProfit + prices[i]
- prices[i - 1], 0); maxV = Math.max(fi, maxV); maxProfit = fi; } return maxV; }
<>3.2 122题 买卖股票的最佳时机 II
<>3.2.1 题目分析
我们先来看一道题目: 第122题:买卖股票的最佳时机 II
需求:给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。
注意: 你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)
示例1
输入: [7,1,5,3,6,4] 输出: 7
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。
示例 2:
输入: [1,2,3,4,5] 输出: 4
解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。
因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。
示例三
输入: [7,6,4,3,1] 输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
<>3.2.2 图解分析
假设我们的数据是:[7, 1, 5, 3, 6, 4]
从上图中,我们可以观察到 A+B+C的和等于差值 DD 所对应的连续峰和谷的高度之差。
<>3.2.3 代码分析
public int maxProfit(int[] prices) { int maxProfit=0; for (int i = 1; i <
prices.length ; i++) { if (prices[i] > prices[i - 1]) { maxProfit += prices[i] -
prices[i - 1]; } } return maxProfit; }
<>四、LeetCode 189 旋转数组
<>4.1 题目分析
我们先来看一道题目: 第189 题:旋转数组
需求:给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数
示例 1:
输入: [1,2,3,4,5,6,7] 和 k = 3 输出: [5,6,7,1,2,3,4]
解释:
向右旋转 1 步: [7,1,2,3,4,5,6]
向右旋转 2 步: [6,7,1,2,3,4,5]
向右旋转 3 步: [5,6,7,1,2,3,4]
示例 2:
输入: [-1,-100,3,99] 和 k = 2 输出: [3,99,-1,-100]
解释:
向右旋转 1 步: [99,-1,-100,3]
向右旋转 2 步: [3,99,-1,-100]
注意:
尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题。
要求使用空间复杂度为 O(1) 的 原地 算法。
<>4.2 图解分析
假设我们的数组为[1,2,3,4,5,6],I=6 且 k=3
通过观察我们可以得到,我们要得到最终的结果。我们只需要将所有元素反转,然后反转前 k 个元素,再反转后面l-k个元素,就能得到想要的结果。
<>4.3代码分析
public static void rotate(int[] nums, int k) { revers(nums, 0, nums.length);
revers(nums, 0, k % nums.length); revers(nums, k % nums.length, nums.length); }
public static void revers(int[] nums, int start, int end) { int length = end -
start; for (int i = 0; i < length / 2; i++) { int num = nums[start + i]; nums[
start+ i] = nums[start + length - i - 1]; nums[start + length - i - 1] = num; }
System.out.println(Arrays.toString(nums)); }