=j){
25 | j++;
26 | }
27 | }
28 | }
29 | }
30 |
31 | public static void main(String[] args) {
32 | int result=0;
33 | int num[]=new int[]{0,1,0,3,12};
34 | moveZeroes(num);
35 | }
36 | }
37 |
38 |
--------------------------------------------------------------------------------
/design_pattern/src/Strategy/Strategy:
--------------------------------------------------------------------------------
1 | 策略模式:Strategy
2 |
3 | 该模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。
4 | 策略模式属于对象行为模式,它通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理。
5 |
6 |
7 | 主要优点如下:
8 | 1.多重条件语句不易维护,而使用策略模式可以避免使用多重条件语句。
9 | 2.策略模式提供了一系列的可供重用的算法族,恰当使用继承可以把算法族的公共代码转移到父类里面,从而避免重复的代码。
10 | 3.策略模式可以提供相同行为的不同实现,客户可以根据不同时间或空间要求选择不同的。
11 | 4.策略模式提供了对开闭原则的完美支持,可以在不修改原代码的情况下,灵活增加新算法。
12 | 5.策略模式把算法的使用放到环境类中,而算法的实现移到具体策略类中,实现了二者的分离。
13 |
14 | 主要缺点如下:
15 | 1.客户端必须理解所有策略算法的区别,以便适时选择恰当的算法类。
16 | 2.策略模式造成很多的策略类。
17 |
18 |
19 | 策略模式的主要角色如下。
20 | 1.抽象策略(Strategy)类:定义了一个公共接口,各种不同的算法以不同的方式实现这个接口,环境角色使用这个接口调用不同的算法,一般使用接口或抽象类实现。
21 | 2.具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现。
22 | 3.环境(Context)类:持有一个策略类的引用,最终给客户端调用。
23 |
24 | 具体应用场景:
25 | 1.一个系统需要动态地在几种算法中选择一种时,可将每个算法封装到策略类中。
26 | 2.一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现,可将每个条件分支移入它们各自的策略类中以代替这些条件语句。
27 | 3.系统中各算法彼此完全独立,且要求对客户隐藏具体算法的实现细节时。
28 | 4.系统要求使用算法的客户不应该知道其操作的数据时,可使用策略模式来隐藏与算法相关的数据结构。
29 | 5.多个类只区别在表现行为不同,可以使用策略模式,在运行时动态选择具体要执行的行为。
30 |
--------------------------------------------------------------------------------
/demo001-100/demo075.java:
--------------------------------------------------------------------------------
1 | package demo001_100;
2 |
3 | /**
4 | * @author:Sun Hongwei
5 | * @2020/2/15 下午1:51
6 | * File Description:颜色分类(荷兰三色旗问题):给定一个包含红色、白色和蓝色,
7 | * 一共 n 个元素的数组,原地对它们进行排序,
8 | * 使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
9 | *
10 | *
11 | * 设置两个指针p1,p2一前一后分别统计0,2的位置,再设置一个遍历数组的指针p
12 | *
13 | */
14 | public class demo075 {
15 | public void sortColors(int[] nums) {
16 | int p1=0,p2=nums.length-1,p=0;//p1:0的位置,p2:2的位置
17 | while(p<=p2){
18 | if(nums[p]==2){
19 | trans(p,p2,nums);
20 | p2--;
21 | }else if(nums[p]==0){
22 | trans(p,p1,nums);
23 | p1++;
24 | p++; //数组前面的数全部已经遍历过了,所以不用考虑数组前的情况
25 | }
26 | else p++;
27 | }
28 | }
29 |
30 | public void trans(int a,int b,int[] nums){
31 | int temp=nums[a];
32 | nums[a]=nums[b];
33 | nums[b]=temp;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/SQL/demo627:
--------------------------------------------------------------------------------
1 | demo627
2 |
3 | 给定一个 salary 表,如下所示,有 m = 男性 和 f = 女性 的值。交换所有的 f 和 m 值(例如,将所有 f 值更改为 m,反之亦然)。要求只使用一个更新(Update)语句,并且没有中间的临时表。
4 |
5 | 注意,您必只能写一个 Update 语句,请不要编写任何 Select 语句。
6 |
7 | 例如:
8 |
9 | | id | name | sex | salary |
10 | |----|------|-----|--------|
11 | | 1 | A | m | 2500 |
12 | | 2 | B | f | 1500 |
13 | | 3 | C | m | 5500 |
14 | | 4 | D | f | 500 |
15 | 运行你所编写的更新语句之后,将会得到以下表:
16 |
17 | | id | name | sex | salary |
18 | |----|------|-----|--------|
19 | | 1 | A | f | 2500 |
20 | | 2 | B | m | 1500 |
21 | | 3 | C | f | 5500 |
22 | | 4 | D | m | 500 |
23 |
24 | _______________________________________________________________
25 |
26 |
27 | 1.case...when...
28 |
29 | UPDATE salary
30 | SET
31 | sex=CASE sex
32 | WHEN 'm' THEN 'f'
33 | ELSE 'm'
34 | END;
35 |
36 |
37 | 2.ASCII互转 !!!
38 | UPDATE salary
39 | SET
40 | sex = char(ascii('m') + ascii('f') - ascii(sex));
41 | //变换前后总和一样
42 |
--------------------------------------------------------------------------------
/demo001-100/demo007.java:
--------------------------------------------------------------------------------
1 | package demo001_100;
2 |
3 | /**
4 | * @author:Sun Hongwei
5 | * @2020/2/12 下午7:57
6 | * File Description:整数反转:给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。
7 | *
8 | *
9 | * 设置个数组依次保存各位数字,再反过来加上
10 | */
11 | public class demo007 {
12 | public static int reverse(int x){
13 | int flag=1,p=0;
14 | int[] out=new int[13];
15 | if(x<0){
16 | flag=-1;
17 | }
18 | x=Math.abs(x);
19 | while(x>0){
20 | out[p++]=x%10;
21 | x=x/10;
22 | }
23 | long result=0;
24 | for(int i=0;iMath.pow(2,31)-1 || result<-Math.pow(2,31)){
28 | return 0;
29 | }
30 | return (int)result * flag;
31 |
32 | }
33 |
34 | public static void main(String[] args) {
35 | int x=1534236469;
36 | int result=reverse(x);
37 | System.out.println(result);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/demo301-400/demo350.java:
--------------------------------------------------------------------------------
1 | import java.lang.reflect.Array;
2 | import java.util.*;
3 |
4 | /**
5 | * @author:Sun Hongwei
6 | * @2020/2/11 下午6:46
7 | * File Description:两个数组的交集 II: 给定两个数组,编写一个函数来计算它们的交集。
8 | *
9 | * 1.输出结果中每个元素出现的次数,应与元素在两个数组中出现的次数一致。
10 | * 2.我们可以不考虑输出结果的顺序。
11 | *
12 | * 先排序,再用两个指针依次遍历
13 | */
14 | public class demo350 {
15 | public int[] intersect(int[] nums1, int[] nums2) {
16 | //先排序
17 | Arrays.sort(nums1);
18 | Arrays.sort(nums2);
19 | int[] res=new int[Math.min(nums1.length,nums2.length)];
20 | int l1=0,l2=0,k=0;
21 | //依次往后遍历,遇到相同的数加进res中
22 | while(l1nums2[l2]){
26 | l2++;
27 | }else{
28 | res[k++]=nums1[l1];
29 | l1++;l2++;
30 | }
31 | }
32 | return Arrays.copyOf(res,k);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/demo101-200/demo102.java:
--------------------------------------------------------------------------------
1 | package demo101_200;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | /**
7 | * @author:Sun Hongwei
8 | * @2020/2/13 下午4:04
9 | * File Description:二叉树的层次遍历:给定一个二叉树,返回其按层次遍历的节点值。
10 | * (即逐层地,从左到右访问所有节点)。
11 | *
12 | *
13 | *
14 | * 深度优先遍历+迭代
15 | */
16 | public class demo102 {
17 | List> levels=new ArrayList<>();
18 |
19 | public List> levelOrder(TreeNode root) {
20 | if(root==null) return levels;
21 | helper(root,0);
22 | return levels;
23 | }
24 |
25 | //辅助函数:遍历整个树结构
26 | public void helper(TreeNode root,int level){
27 | if(levels.size()==level){
28 | //如果还没有level这个List
29 | levels.add(new ArrayList());
30 | }
31 | //添加元素
32 | levels.get(level).add(root.val);
33 | if(root.left!=null) helper(root.left,level+1);
34 | if(root.right!=null) helper(root.right,level+1);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/demo201-300/demo215.java:
--------------------------------------------------------------------------------
1 | package demo201_300;
2 |
3 | import java.util.PriorityQueue;
4 |
5 | /**
6 | * @author:Sun Hongwei
7 | * @2020/2/12 下午4:01
8 | * File Description:数组中的第K个最大元素:在未排序的数组中找到第 k 个最大的元素。
9 | * 需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
10 | *
11 | *
12 | * PriorityQueue表示堆
13 | * 堆取数(堆顶即为最小值)和排序的时间复杂度都很低
14 | *
15 | */
16 | public class demo215 {
17 | //数组中第k大的元素(创建堆)
18 | public static int findKthLargest(int[] nums, int k){
19 | PriorityQueue p=new PriorityQueue();
20 |
21 | //遍历数组放入堆中:
22 | for(int n:nums){
23 | p.add(n);
24 | if(p.size()>k){ //如果堆的容量大于k时
25 | p.poll(); //每次从堆顶移除最小值
26 | }
27 | }
28 | return p.poll();
29 |
30 | }
31 |
32 | public static void main(String args[]){
33 | int[] nums=new int[]{2,3,6,8,4,1};
34 | int k=2;
35 | int x=findKthLargest(nums,k);
36 | System.out.println(x);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/SQL/demo181:
--------------------------------------------------------------------------------
1 | demo181
2 |
3 | Employee 表包含所有员工,他们的经理也属于员工。每个员工都有一个 Id,此外还有一列对应员工的经理的 Id。
4 |
5 | +----+-------+--------+-----------+
6 | | Id | Name | Salary | ManagerId |
7 | +----+-------+--------+-----------+
8 | | 1 | Joe | 70000 | 3 |
9 | | 2 | Henry | 80000 | 4 |
10 | | 3 | Sam | 60000 | NULL |
11 | | 4 | Max | 90000 | NULL |
12 | +----+-------+--------+-----------+
13 | 给定 Employee 表,编写一个 SQL 查询,该查询可以获取收入超过他们经理的员工的姓名。在上面的表格中,Joe 是唯一一个收入超过他的经理的员工。
14 |
15 | +----------+
16 | | Employee |
17 | +----------+
18 | | Joe |
19 | +----------+
20 |
21 | _______________________________________________________________
22 |
23 | 1.拆成两个表再用ManagerId=Id整合一起时比较Salary
24 |
25 | SELECT A.Name as Employee
26 | FROM Employee as A,Employee as B
27 | WHERE A.ManagerId=B.Id
28 | AND A.Salary>B.Salary;
29 |
30 | 2.用JOIN...ON整合一起
31 | SELECT A.Name as Employee
32 | FROM Employee as A JOIN Employee as B
33 | ON A.ManagerId=B.Id
34 | AND A.Salary>B.Salary;
--------------------------------------------------------------------------------
/demo301-400/demo378.java:
--------------------------------------------------------------------------------
1 | package demo301_400;
2 |
3 | import java.util.Comparator;
4 | import java.util.PriorityQueue;
5 | import java.util.Queue;
6 |
7 | /**
8 | * @author:Sun Hongwei
9 | * @2020/2/15 下午1:17
10 | * File Description:有序矩阵中第K小的元素: 给定一个 n x n 矩阵,
11 | * 其中每行和每列元素均按升序排序,找到矩阵中第k小的元素。
12 | *
13 | * 用优先队列PriorityQueue实现最大堆(容量为k),最后返回堆顶值。
14 | */
15 | public class demo378{
16 | public int kthSmallest(int[][] matrix, int k) {
17 | PriorityQueue p=new PriorityQueue(new Comparator() {
18 | @Override
19 | public int compare(Integer p1, Integer p2) {
20 | return p2-p1; //最大堆
21 | }
22 | });
23 | for(int i=0;ik) p.poll(); //当堆元素超过k个元素,去掉当前最大值
27 | }
28 | }
29 | return p.poll();
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/demo901-1000/demo946.java:
--------------------------------------------------------------------------------
1 | package demo901_1000;
2 |
3 | import java.util.Stack;
4 |
5 | /**
6 | * @author:Sun Hongwei
7 | * @2020/2/28 下午6:12
8 | * File Description:栈的压入、弹出序列: 输入两个整数序列,第一个序列表示栈的压入顺序,
9 | * 请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。
10 | * 例如,序列 {1,2,3,4,5} 是某栈的压栈序列,序列 {4,5,3,2,1} 是该压栈序列对应的一个弹出序列,
11 | * 但 {4,3,5,1,2} 就不可能是该压栈序列的弹出序列。
12 | *
13 | *
14 | * 用一个stack模拟栈push和pop的过程
15 | */
16 | public class demo946 {
17 | public boolean validateStackSequences(int[] pushed, int[] popped) {
18 | if(pushed.length!=popped.length){
19 | return false;
20 | }
21 | Stack stack=new Stack<>();
22 | int j=0;
23 | for(int i:pushed){
24 | stack.push(i); //先依次把每个数压入栈里
25 | while(!stack.isEmpty() && j=1){
10 | shellInsertSort(array,dk);
11 | if(dk==1){
12 | break;
13 | }
14 | dk=dk/3+1;
15 | }
16 | return array;
17 | }
18 |
19 | private static void shellInsertSort(int[] array,int dk){
20 | //每次步长为dk的插入排序
21 | for(int i=dk;i=0 && num=high){
24 | return false;
25 | }
26 | if(!isValid(root.left,low,root.val)){
27 | return false;
28 | }
29 | if(!isValid(root.right,root.val,high)){
30 | return false;
31 | }
32 | return true;
33 | }
34 |
35 | public boolean isValidBST(TreeNode root) {
36 | return isValid(root,null,null);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/offer/m13.java:
--------------------------------------------------------------------------------
1 | package offer;
2 |
3 | /**
4 | * @author:Sun Hongwei
5 | * @2020/2/28 上午9:53
6 | * File Description:机器人的运动范围:地上有一个m行n列的方格,从坐标[0,0]到坐标[m-1,n-1]。
7 | * 一个机器人从坐标[0, 0]的格子开始移动,它每次可以向左、右、上、下移动一格(不能移动到方格外),
8 | * 也不能进入行坐标和列坐标的数位之和大于k的格子。
9 | *
10 | *
11 | * 深度优先遍历DFS
12 | */
13 | public class m13 {
14 | private int m,n,k,count=0;
15 | private boolean[][] visited;
16 | public int movingCount(int m, int n, int k) {
17 | this.visited=new boolean[m][n]; //访问标志位
18 | this.m=m;
19 | this.k=k;
20 | this.n=n;
21 | dfs(0,0);
22 | return count;
23 | }
24 | public void dfs(int i,int j){
25 | if(i<0 || i>=m || j<0 || j>=n || visited[i][j]==true){
26 | return;
27 | }//遇到边界
28 |
29 | if((i%10+i/10)+(j%10+j/10)>k){
30 | return; //数位之和超过预定值
31 | }
32 | visited[i][j]=true;
33 | count++;
34 |
35 | //遍历下一格
36 | dfs(i-1,j);
37 | dfs(i+1,j);
38 | dfs(i,j-1);
39 | dfs(i,j+1);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/demo101-200/demo152.java:
--------------------------------------------------------------------------------
1 | package demo101_200;
2 |
3 | /**
4 | * @author:Sun Hongwei
5 | * @2020/2/14 下午10:39
6 | * File Description:乘积最大子序列:给定一个整数数组 nums ,
7 | * 找出一个序列中乘积最大的连续子序列(该序列至少包含一个数)。
8 | *
9 | *
10 | * 动态规划:d(p)=max(d(max)(p-1)*nums[p],nums[p])
11 | * 并且考虑负数情况 d(p)=max(d(min)(p-1)*nums[p],nums[p])
12 | *
13 | * 始终储存两个常量,最大值和最小值
14 | *
15 | */
16 | public class demo152 {
17 | public int maxProduct(int[] nums) {
18 | int maxnum=Integer.MIN_VALUE;
19 | int imax=1,imin=1,temp;
20 | for(int i=0;i0 && nums[i]-nums[i-1]>1 && nums[i-1]!=0) {
24 | if (nums[i]-nums[i-1]-1>count) { //如果0不够替代中间的差值,返回false
25 | return false;
26 | }else {
27 | count-=(nums[i]-nums[i-1]-1);
28 | }
29 | }else if(i>0 && nums[i]==nums[i-1]){ //如果遇到重复不为0的牌,直接返回false
30 | return false;
31 | }
32 | }
33 | return true;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/demo001-100/demo090.java:
--------------------------------------------------------------------------------
1 | package demo001_100;
2 |
3 | import java.util.ArrayList;
4 | import java.util.Arrays;
5 | import java.util.List;
6 |
7 | /**
8 | * @author:Sun Hongwei
9 | * @2020/2/14 下午2:15
10 | * File Description:子集 II:给定一个可能包含重复元素的整数数组nums,
11 | * 返回该数组所有可能的子集(幂集)。
12 | *
13 | * 回溯,大致同78题,先排序,遍历时去掉重复的情况
14 | */
15 | public class demo090 {
16 | List> results=new ArrayList<>();
17 | public List> subsetsWithDup(int[] nums) {
18 | Arrays.sort(nums);
19 | backtrack(nums,new ArrayList(),0);
20 | return results;
21 | }
22 | //回溯
23 | public void backtrack(int[] nums,ArrayList temp, int start){
24 | results.add(new ArrayList<>(temp));
25 |
26 | for(int i=start;istart && nums[i]==nums[i-1]) continue;
29 |
30 | temp.add(nums[i]);
31 | backtrack(nums,temp,i+1);
32 | temp.remove(temp.size()-1);
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/demo101-200/demo200.java:
--------------------------------------------------------------------------------
1 | package demo101_200;
2 |
3 | /**
4 | * @author:Sun Hongwei
5 | * @2020/2/21 下午1:17
6 | * File Description:岛屿数量: 给定一个由'1'(陆地)和'0'(水)组成的的二维网格,计算岛屿的数量。
7 | * 一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。
8 | *
9 | *
10 | * 深度优先遍历DFS
11 | */
12 | public class demo200 {
13 | private char[][] grid;
14 | public int numIslands(char[][] grid) {
15 | this.grid=grid;
16 | int count=0;
17 | for(int i=0;i=grid.length || j<0 || j>=grid[0].length ) return;
32 | if(grid[i][j]=='0') return;
33 | grid[i][j]='0';
34 | dfs(i-1,j);
35 | dfs(i+1,j);
36 | dfs(i,j-1);
37 | dfs(i,j+1);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/demo201-300/demo202.java:
--------------------------------------------------------------------------------
1 | package demo201_300;
2 |
3 | import java.util.HashSet;
4 |
5 | /**
6 | * @author:Sun Hongwei
7 | * @2020/2/12 下午3:52
8 | * File Description:快乐数:一个“快乐数”定义为:对于一个正整数,每一次将该数替换为
9 | * 它每个位置上的数字的平方和,然后重复这个过程直到这个数变为 1,
10 | * 也可能是无限循环但始终变不到 1。如果可以变为 1,那么这个数就是快乐数。
11 | *
12 | *
13 | * hashset的方法,防止循环的现象发生,剩下的依次计算即可。
14 | */
15 | public class demo202 {
16 | public static boolean isHappy(int n) {
17 | HashSet set=new HashSet();
18 | set.add(n);
19 | while(n!=1){
20 | n=PowerSum(n);
21 | if(set.contains(n)) return false;
22 | else set.add(n);
23 | }
24 | return true;
25 | }
26 |
27 | public static int PowerSum(int x){
28 | int sum=0;
29 | while(x!=0){
30 | sum+=(x%10)*(x%10);
31 | x/=10;
32 | }
33 | return sum;
34 | }
35 |
36 | public static void main(String[] args) {
37 | int n=19;
38 | System.out.println(isHappy(n));
39 | }
40 | }
--------------------------------------------------------------------------------
/demo201-300/demo236.java:
--------------------------------------------------------------------------------
1 | package demo201_300;
2 |
3 | /**
4 | * @author:Sun Hongwei
5 | * @2020/2/19 下午11:40
6 | * File Description:二叉树的最近公共祖先: 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
7 | *
8 | *
9 | * DFS+遍历
10 | * 1.若子树存在p,q公共节点,返回该公共节点
11 | * 2.若不存在公共节点,但是存在p,q之一,则返回此节点
12 | * 2.要是p,q都不粗在,返回null
13 | */
14 | public class demo236 {
15 | public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q){
16 | //若当前节点是null,或者p,q之一直接返回该节点
17 | if(root==null || root==p || root==q){
18 | return root;
19 | }
20 | TreeNode left=lowestCommonAncestor(root.left,p,q);
21 | //若左子树存在公共节点,返回值不是p或q,则直接返回该节点,不需要再遍历右子树
22 | if(left!=null && left!=p && left!=q){
23 | return left;
24 | }
25 | TreeNode right=lowestCommonAncestor(root.right,p,q);
26 | //若左右子树都返回非空节点值,说明肯定一个是p,一个是q,那么此时这个节点就是公共节点
27 | if(right!=null && left!=null){
28 | return root;
29 | }else { //若左子树返回的null,则返回值肯定是在右子树上
30 | return left==null?right:left;
31 | }
32 |
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/design_pattern/src/TemplateMethod/TemplateMethod:
--------------------------------------------------------------------------------
1 | 模板方法模式:TemplateMethod
2 |
3 | 定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。
4 | 它是一种类行为型模式。
5 |
6 | 主要优点如下:
7 | 1.它封装了不变部分,扩展可变部分。它把认为是不变部分的算法封装到父类中实现,而把可变部分算法由子类继承实现,便于子类继续扩展。
8 | 2.它在父类中提取了公共的部分代码,便于代码复用。
9 | 3.部分方法是由子类实现的,因此子类可以通过扩展方式增加相应的功能,符合开闭原则。
10 |
11 | 该模式的主要缺点如下:
12 | 1.对每个不同的实现都需要定义一个子类,这会导致类的个数增加,系统更加庞大,设计也更加抽象。
13 | 2.父类中的抽象方法由子类实现,子类执行的结果会影响父类的结果,这导致一种反向的控制结构,它提高了代码阅读的难度。
14 |
15 |
16 | 模板方法模式包含以下主要角色。
17 |
18 | (1) 抽象类(Abstract Class):负责给出一个算法的轮廓和骨架。它由一个模板方法和若干个基本方法构成。这些方法的定义如下。
19 |
20 | ① 模板方法:定义了算法的骨架,按某种顺序调用其包含的基本方法。
21 |
22 | ② 基本方法:是整个算法中的一个步骤,包含以下几种类型。
23 | 抽象方法:在抽象类中申明,由具体子类实现。
24 | 具体方法:在抽象类中已经实现,在具体子类中可以继承或重写它。
25 | 钩子方法:在抽象类中已经实现,包括用于判断的逻辑方法和需要子类重写的空方法两种。
26 |
27 | (2) 具体子类(Concrete Class):实现抽象类中所定义的抽象方法和钩子方法,它们是一个顶级逻辑的一个组成步骤
28 |
29 |
30 | 模板方法模式通常适用于以下场景:
31 | 1.算法的整体步骤很固定,但其中个别部分易变时,这时候可以使用模板方法模式,将容易变的部分抽象出来,供子类实现。
32 | 2.当多个子类存在公共的行为时,可以将其提取出来并集中到一个公共父类中以避免代码重复。首先,要识别现有代码中的不同之处,并且将不同之处分离为新的操作。最后,用一个调用这些新的操作的模板方法来替换这些不同的代码。
33 | 3.当需要控制子类的扩展时,模板方法只在特定点调用钩子操作,这样就只允许在这些点进行扩展。
34 |
35 |
36 |
--------------------------------------------------------------------------------
/demo001-100/demo011.java:
--------------------------------------------------------------------------------
1 | package demo001_100;
2 |
3 | /**
4 | * @author:Sun Hongwei
5 | * @2020/2/12 下午8:12
6 | * File Description:盛最多水的容器: 给定 n 个非负整数 a1,a2,...,an,
7 | * 每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,
8 | * 垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线,
9 | * 使得它们与 x 轴共同构成的容器可以容纳最多的水。
10 | *
11 | *
12 | * 设置两个指针,一前一后遍历
13 | *
14 | */
15 | public class demo011 {
16 | //盛最多水的容器:双指针法
17 | public static int maxArea(int[] height) {
18 | int area=0,left=0,right=height.length-1;
19 | while(left col=new HashSet(); //列号
18 | Set row=new HashSet(); //行号
19 |
20 | for(int i=0;i> generate(int numRows) {
13 | List> triangle=new ArrayList>();
14 | if(numRows==0) return triangle;
15 |
16 | //第一行
17 | triangle.add(new ArrayList<>());
18 | triangle.get(0).add(1);
19 |
20 | //下面开始动态规划:
21 | for(int i=1;i row=new ArrayList();
23 | List previous=triangle.get(i-1); //前一行
24 |
25 | row.add(1); //每行第一个
26 | for(int j=1;j=5;
41 |
42 | 2.构建临时表:
43 | SELECT class
44 | FROM
45 | ( //临时表
46 | SELECT class,COUNT(DISTINCT student) as num
47 | FROM courses
48 | GROUP BY class
49 | )as classnum
50 | WHERE num>1;
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/demo001-100/demo084.java:
--------------------------------------------------------------------------------
1 | package demo001_100;
2 |
3 | import java.util.Stack;
4 |
5 | /**
6 | * @author:Sun Hongwei
7 | * @2020/2/19 下午8:26
8 | * File Description:柱状图中最大的矩形:给定 n 个非负整数,用来表示柱状图中各个柱子的高度。
9 | * 每个柱子彼此相邻,且宽度为 1 。求在该柱状图中,能够勾勒出来的矩形的最大面积。
10 | *
11 | *
12 | *用栈储存:
13 | * 1.若当前高度小于之前的,依次按照计算高度之前的最大面积,比较后并弹出
14 | * 2.遍历一遍后,用当前的最小高度乘上n进行比较
15 | */
16 | public class demo084 {
17 | public int largestRectangleArea(int[] heights) {
18 | Stack stack=new Stack();
19 | stack.push(-1);
20 | int maxarea=0;
21 | //压入栈中,遍历
22 | for(int i=0;i=heights[i]){
24 | maxarea=Math.max(maxarea,heights[stack.pop()]*(i-stack.peek()-1));
25 | }
26 | stack.push(i);
27 | }
28 | //将栈中剩余元素弹出栈
29 | while (stack.peek()!=-1){
30 | maxarea=Math.max(maxarea,heights[stack.pop()]*
31 | (heights.length-stack.peek()-1));
32 | }
33 | return maxarea;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/design_pattern/out/production/design_pattern/TemplateMethod/TemplateMethod:
--------------------------------------------------------------------------------
1 | 模板方法模式:TemplateMethod
2 |
3 | 定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。
4 | 它是一种类行为型模式。
5 |
6 | 主要优点如下:
7 | 1.它封装了不变部分,扩展可变部分。它把认为是不变部分的算法封装到父类中实现,而把可变部分算法由子类继承实现,便于子类继续扩展。
8 | 2.它在父类中提取了公共的部分代码,便于代码复用。
9 | 3.部分方法是由子类实现的,因此子类可以通过扩展方式增加相应的功能,符合开闭原则。
10 |
11 | 该模式的主要缺点如下:
12 | 1.对每个不同的实现都需要定义一个子类,这会导致类的个数增加,系统更加庞大,设计也更加抽象。
13 | 2.父类中的抽象方法由子类实现,子类执行的结果会影响父类的结果,这导致一种反向的控制结构,它提高了代码阅读的难度。
14 |
15 |
16 | 模板方法模式包含以下主要角色。
17 |
18 | (1) 抽象类(Abstract Class):负责给出一个算法的轮廓和骨架。它由一个模板方法和若干个基本方法构成。这些方法的定义如下。
19 |
20 | ① 模板方法:定义了算法的骨架,按某种顺序调用其包含的基本方法。
21 |
22 | ② 基本方法:是整个算法中的一个步骤,包含以下几种类型。
23 | 抽象方法:在抽象类中申明,由具体子类实现。
24 | 具体方法:在抽象类中已经实现,在具体子类中可以继承或重写它。
25 | 钩子方法:在抽象类中已经实现,包括用于判断的逻辑方法和需要子类重写的空方法两种。
26 |
27 | (2) 具体子类(Concrete Class):实现抽象类中所定义的抽象方法和钩子方法,它们是一个顶级逻辑的一个组成步骤
28 |
29 |
30 | 模板方法模式通常适用于以下场景:
31 | 1.算法的整体步骤很固定,但其中个别部分易变时,这时候可以使用模板方法模式,将容易变的部分抽象出来,供子类实现。
32 | 2.当多个子类存在公共的行为时,可以将其提取出来并集中到一个公共父类中以避免代码重复。首先,要识别现有代码中的不同之处,并且将不同之处分离为新的操作。最后,用一个调用这些新的操作的模板方法来替换这些不同的代码。
33 | 3.当需要控制子类的扩展时,模板方法只在特定点调用钩子操作,这样就只允许在这些点进行扩展。
34 |
35 |
36 |
--------------------------------------------------------------------------------
/demo101-200/demo189.java:
--------------------------------------------------------------------------------
1 | package demo101_200;
2 |
3 | /**
4 | * @author:Sun Hongwei
5 | * @2020/2/12 下午10:29
6 | * File Description:旋转数组: 给定一个数组,将数组中的元素向右移动k个位置,其中k是非负数。
7 | *
8 | *
9 | * 反转三次即可:1. 从第1~n-k个数反转
10 | * 2. 从第(n-k+1)~n个数反转
11 | * 3. 从第1~n个数反转
12 | */
13 | public class demo189 {
14 | public static void rotate(int[] nums, int k) {
15 | k=k%nums.length; //防止k比nums.length要大
16 | reverse(nums,0,nums.length-k-1);
17 | reverse(nums,nums.length-k,nums.length-1);
18 | reverse(nums,0,nums.length-1);
19 | }
20 |
21 | public static void reverse(int[] nums,int start,int end){
22 | while(start=10){ //某一位是0的情况也需要考虑
30 | dp[i]=dp[i-1]+dp[i-2];
31 | }else{
32 | dp[i]=dp[i-1];
33 | }
34 | }
35 | return dp[numc.length-1];
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/SQL/demo183:
--------------------------------------------------------------------------------
1 | demo183
2 |
3 | 某网站包含两个表,Customers 表和 Orders 表。编写一个 SQL 查询,找出所有从不订购任何东西的客户。
4 |
5 | Customers 表:
6 |
7 | +----+-------+
8 | | Id | Name |
9 | +----+-------+
10 | | 1 | Joe |
11 | | 2 | Henry |
12 | | 3 | Sam |
13 | | 4 | Max |
14 | +----+-------+
15 | Orders 表:
16 |
17 | +----+------------+
18 | | Id | CustomerId |
19 | +----+------------+
20 | | 1 | 3 |
21 | | 2 | 1 |
22 | +----+------------+
23 | 例如给定上述表格,你的查询应返回:
24 |
25 | +-----------+
26 | | Customers |
27 | +-----------+
28 | | Henry |
29 | | Max |
30 | +-----------+
31 |
32 | _______________________________________________________________
33 |
34 |
35 | 1.NOT IN:
36 |
37 | SELECT Customers.Name as Customers
38 | FROM Customers
39 | WHERE Customers.Id
40 | NOT IN
41 | (
42 | SELECT CustomerId FROM Orders
43 | );
44 |
45 |
46 |
47 | 2.LEFT JOIN:
48 | 左连接(以左表为核心): 从左表(table1)返回所有的行,即使右表(table2)中没有匹配。如果右表中没有匹配,则结果为 NULL。
49 |
50 | SELECT Customers.Name as Customers
51 | FROM Customers
52 | LEFT JOIN Orders
53 | ON Customers.Id=Orders.CustomerId
54 | WHERE Orders.CustomerId is null;
55 |
56 |
57 |
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/offer/m09.java:
--------------------------------------------------------------------------------
1 | package offer;
2 |
3 | import java.util.Stack;
4 |
5 | /**
6 | * @author:Sun Hongwei
7 | * @2020/2/27 下午10:32
8 | * File Description:用两个栈实现队列: 用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead ,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead 操作返回 -1 )
9 | *
10 | *
11 | *删除队头元素: 若stack2为空,把stack1中的元素全部取出压入到stack2中即可
12 | */
13 | public class m09 {
14 | class CQueue {
15 | private Stack stack1; //stack1用于储存元素
16 | private Stack stack2; //stack2用于辅助,操作删除队头元素
17 |
18 | public CQueue() {
19 | stack1=new Stack();
20 | stack2=new Stack();
21 | }
22 |
23 | public void appendTail(int value) {
24 | stack1.push(value);
25 | }
26 |
27 | public int deleteHead() {
28 | if(stack1.isEmpty() && stack2.isEmpty()){
29 | return -1;
30 | }
31 | if(stack2.isEmpty()){
32 | while (!stack1.isEmpty()){
33 | stack2.push(stack1.pop());
34 | }
35 | }
36 | return stack2.pop();
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/demo001-100/demo034.java:
--------------------------------------------------------------------------------
1 | package demo001_100;
2 |
3 | /**
4 | * @author:Sun Hongwei
5 | * @2020/2/14 下午8:05
6 | * File Description:在排序数组中查找元素的第一个和最后一个位置:
7 | * 给定一个按照升序排列的整数数组 nums,和一个目标值 target。
8 | * 找出给定目标值在数组中的开始位置和结束位置。
9 | * 你的算法时间复杂度必须是 O(log n) 级别。
10 | *
11 | *
12 | * 二分查找改进:找到target后往前往后遍历(也可以再写个辅助函数继续二分查找)
13 | */
14 | public class demo034 {
15 | public int[] searchRange(int[] nums, int target) {
16 | int[] ans=new int[]{-1,-1};
17 | int l=0,r=nums.length-1,mid,p;
18 | while(ltarget){
21 | r=mid-1;
22 | }else if(nums[mid]=0 && nums[p]==target) p--;
33 | ans[0]=p+1;
34 | break;
35 | }
36 | }
37 | return ans;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/demo301-400/demo347.java:
--------------------------------------------------------------------------------
1 | package demo301_400;
2 |
3 | import java.util.*;
4 |
5 | /**
6 | * @author:Sun Hongwei
7 | * @2020/2/12 下午8:36
8 | * File Description:前 K 个高频元素:给定一个非空的整数数组,返回其中出现频率前 k 高的元素。
9 | *
10 | * 用一个hashmap统计个数
11 | * 并建立一个PriorityQueue用堆来筛选前k个元素
12 | */
13 | public class demo347 {
14 | public List topKFrequent(int[] nums, int k) {
15 | Map map=new HashMap(); //存储个数
16 | for(int n:nums){
17 | //map.getOrDefault(x1,x2):默认取x1的值,若为空取x2
18 | map.put(n,map.getOrDefault(n,0)+1);
19 | }
20 |
21 | PriorityQueue heap=new PriorityQueue
22 | ((n1,n2) ->map.get(n1)-map.get(n2)); //按照value值从小到大建堆
23 |
24 | for(int n:map.keySet()){
25 | heap.add(n);
26 | if(heap.size()>k){
27 | heap.poll();
28 | }
29 | }
30 |
31 | List ktop=new ArrayList();
32 | while (!heap.isEmpty()){
33 | ktop.add(heap.poll()); //把堆中元素防止arraylist中
34 | }
35 | Collections.reverse(ktop); //数组翻转
36 | return ktop;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/demo501-600/demo581.java:
--------------------------------------------------------------------------------
1 | package demo501_600;
2 |
3 | /**
4 | * @author:Sun Hongwei
5 | * @2020/2/21 下午9:55
6 | * File Description:最短无序连续子数组: 给定一个整数数组,你需要寻找一个连续的子数组,
7 | * 如果对这个子数组进行升序排序,那么整个数组都会变为升序排序。
8 | * 你找到的子数组应是最短的,请输出它的长度。
9 | *
10 | *
11 | *
12 | * 无序子数组中: 最小元素的实际正确位置决定了左边界,最大元素的实际正确位置决定了右边界
13 | *
14 | * 先正向遍历找到最小的降序序列中最小的数min,再逆向找到最大的数max
15 | * 并找到min,max应该所处的位置即可。
16 | */
17 | public class demo581 {
18 | public int findUnsortedSubarray(int[] nums) {
19 | int min=Integer.MAX_VALUE,max=Integer.MIN_VALUE;
20 | for (int i=1;i=0;right--){
33 | if(max>nums[right]){
34 | break;
35 | }
36 | }
37 | return rightp2.Id;
29 |
30 | 改成删除即可:
31 |
32 | DELETE p1
33 | FROM Person p1,Person p2
34 | WHERE p1.Email = p2.Email
35 | AND p1.Id > p2.Id;
36 |
37 | 2.Group by 和 not in //先把每种Email用group by统计出来,保留每种最小的id,然后删除(not in)的记录
38 | DELETE FROM Person
39 | WHERE Id not in
40 | (
41 | SELECT p.minid
42 | FROM
43 | (
44 | SELECT min(Id) as minid
45 | FROM Person
46 | GROUP BY Email
47 | )
48 | as p
49 | )
50 | );
51 |
--------------------------------------------------------------------------------