剑指Offer(java答案)
- 剑指Offerjava答案
- 3二维数组中的查找
- 4替换空格
- 5从尾到头打印链表
- 6重建二叉树
- 7用两个栈实现队列
- 8旋转数组的最小数字
- 9斐波那契数列
- 10二进制中1的个数
- 11数值的整数次方
- 12打印1到最大的n位数
- 13在O1时间删除链表结点
- 14调整数组顺序使奇数位于偶数前面
- 15链表中倒数第k个结点
- 16反转链表
- 17合并两个排序的链表
- 18树的子结构
- 19二叉树的镜像
- 20顺时针打印矩阵
- 21包含min函数的栈
- 22栈的压入弹出序列
- 23从上往下打印二叉树层次遍历
- 24二叉搜索树的后序遍历序列
- 25二叉树中和为某一值的路径
- 26复杂链表的复制
- 27二叉搜索树与双向链表
- 28字符串的排列
- 29数组中出现次数超过一半的数字
- 30最小的K个数
- 31连续子数组的最大和
- 32整数中1出现的次数从1到n整数中1出现的次数
- 33把数组排成最小的数
- 34丑数
- 35第一个只出现一次的字符
- 36数组中的逆序对
- 37两个链表的第一个公共交点
- 38数字在排序数组中出现的次数
- 39二叉树的深度
- 40-数组只指出现一次的数字
- 异或去重
- 11-1000放在含有1001个元素的数组中只有唯一的一个元素值重复其它均只出现一次每个数组元素只能访问一次设计一个算法将它找出来不用辅助存储空间能否设计一个算法实现
- 2一个整型数组里除了两个数字之外其他的数字都出现了两次请写程序找出这两个只出现一次的数字
- 3题目一个int数组中有三个数字abc只出现一次其他数字都出现了两次请找出三个只出现一次的数字
- 41和为S的两个数字
- 42反转单词
- 44扑克牌的顺序
- 45约瑟夫环问题圆圈中最后一个数字
- 46求123n
- 47不用加减乘除做加法
- 49把字符串转换成整数
- 51数组中重复的数
- 52构建乘积数组
- 53正则表达式匹配
- 54表示数值的字符串
- 55字符流中第一个不重复的字符
- 56链表中环的入口结点
- 57删除链表中重复的结点
- 58二叉树的下一个结点
- 59对称的二叉树
- 60把二叉树打印成多行
- 61按之字形顺序打印二叉树
- 62序列化二叉树
- 63二叉搜索树的第K个节点
- 64数据流中的中位数
- 65滑动窗口的最大值
3、二维数组中的查找
题目描述
在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
1 | 2 | 8 | 9 | 24912471013681115思路: 从右上角开始,若小,向下走,删除一行,若大,向左走,删除一列
public class Solution { public boolean Find(int [][] array,int target) { int row=0; int col=array[0].length-1; while(row<=array.length-1&&col>=0){ if(target==array[row][col]) return true; else if(target>array[row][col]) row++; else col--; } return false; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
4、替换空格
题目描述
请实现一个函数,将一个字符串中的空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
思路:先遍历一遍字符,统计空格数,由此计算替换之后的总长度。然后从后往前加载字符串,如果发现空格,就替换20%
public class Solution { public String replaceSpace(StringBuffer str) { int spacenum = 0; for(int i=0;i<str.length();i++){ if(str.charAt(i)==' ') spacenum++; } int indexold = str.length()-1; int newlength = str.length() + spacenum*2; int indexnew = newlength-1; str.setLength(newlength); for(;indexold>=0 && indexold<newlength;--indexold){ if(str.charAt(indexold) == ' '){ str.setCharAt(indexnew--, '0'); str.setCharAt(indexnew--, '2'); str.setCharAt(indexnew--, '%'); }else{ str.setCharAt(indexnew--, str.charAt(indexold)); } } return str.toString(); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
5、从尾到头打印链表
题目描述:
输入一个链表,从尾到头打印链表每个节点的值。
思路1:栈
/*** public class ListNode {* int val;* ListNode next = null;* ListNode(int val) {* this.val = val;* }* }*/import java.util.Stack;import java.util.ArrayList;public class Solution { public ArrayList<Integer> printListFromTailToHead(ListNode listNode) { if(listNode == null){ ArrayList list = new ArrayList(); return list; } Stack<Integer> stk = new Stack<Integer>(); while(listNode != null){ stk.push(listNode.val); listNode = listNode.next; } ArrayList<Integer> arr = new ArrayList<Integer>(); while(!stk.isEmpty()){ arr.add(stk.pop()); } return arr; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
思路2:递归
public class Solution { public void printListFromTailToHead(ListNode listNode) { if(listNode != null){ if(listNode.next != null){ printListFromTailToHead(listNode.next); } System.out.print(""+listNode.var); } }}
6、重建二叉树
题目描述:已知中序和前序,请重建二叉树
/** * Definition for binary tree * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */public class Solution { public TreeNode reConstructBinaryTree(int [] pre,int [] in) { TreeNode root=reConstructBinaryTree(pre,0,pre.length-1,in,0,in.length-1); return root; } private TreeNode reConstructBinaryTree(int [] pre,int startPre,int endPre,int [] in,int startIn,int endIn) { if(startPre>endPre||startIn>endIn) return null; TreeNode root=new TreeNode(pre[startPre]); for(int i=startIn;i<=endIn;i++) if(in[i]==pre[startPre]){ root.left=reConstructBinaryTree(pre,startPre+1,startPre+i-startIn,in,startIn,i-1); root.right=reConstructBinaryTree(pre,i-startIn+startPre+1,endPre,in,i+1,endIn); } return root; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
引申:已知中序和后序求前序
package com.zhuang.tree;public class Main { public static class TreeNode { int val; TreeNode left; TreeNode right; TreeNode(int x) { val = x; } } public static TreeNode reConstructBinaryTree(int [] post,int [] in) { TreeNode root=reConstructBinaryTree(post,0,post.length-1,in,0,in.length-1); return root; } private static TreeNode reConstructBinaryTree(int [] post,int startPost,int endPost,int [] in,int startIn,int endIn) { if(startPost>endPost||startIn>endIn) return null; TreeNode root=new TreeNode(post[endPost]); for(int i=startIn;i<=endIn;i++) if(in[i]==post[endPost]){ root.left=reConstructBinaryTree(post,startPost,startPost+i-startIn-1,in,startIn,i-1); root.right=reConstructBinaryTree(post,startPost+i-startIn,endPost-1,in,i+1,endIn); } return root; } public static void preOrder(TreeNode root){ if(root == null){ return; } System.out.println(root.val); preOrder(root.left); preOrder(root.right); } public static void main(String[] args){ int[] post = {2,4,3,1,6,7,5}; int[] in = {1,2,3,4,5,6,7}; TreeNode root = reConstructBinaryTree(post, in); preOrder(root); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
7、用两个栈实现队列
题目描述
用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。
思路:入栈给stack1,出栈时,若stack2不为空,则出栈,若为空,把stack1的内容全都放入stack2,然后再出栈
import java.util.Stack;public class Solution { Stack<Integer> stack1 = new Stack<Integer>(); Stack<Integer> stack2 = new Stack<Integer>(); public void push(int node) { stack1.push(node); } public int pop() { while(!stack2.isEmpty()) { return stack2.pop(); } while(!stack1.isEmpty()) { stack2.push(stack1.pop()); } return stack2.pop(); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
8、旋转数组的最小数字
题目描述
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
import java.util.ArrayList;public class Solution { public int minNumberInRotateArray(int[] array) { if (array == null || array.length == 0) { return 0; } int low = 0; int up = array.length - 1; int mid = low; while (array[low] >= array[up]) { if (up - low == 1) { mid = up; break; } if (array[low] == array[up] && array[mid] == array[low]) return MinInOrder(array); mid = (low + up) / 2; if (array[mid] >= array[low]) low = mid; else if (array[mid] <= array[up]) up = mid; } return array[mid]; } private int MinInOrder(int[] array) { int min = array[0]; for (int i = 1; i < array.length; i++) { if (array[i] < min) { min = array[i]; } } return min; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
9、斐波那契数列
题目描述
大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项。
思路1:递归,简洁但效率不高
public int Fibonacci(int n) { if(n<=0) return 0; if(n==1) return 1; return Fibonacci(n-1) + Fibonacci(n-2); }
思路2:循环,O(N)
public class Solution { public int Fibonacci(int n) { int preNum=1; int prePreNum=0; int result=0; if(n==0) return 0; if(n==1) return 1; for(int i=2;i<=n;i++){ result=preNum+prePreNum; prePreNum=preNum; preNum=result; } return result; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
扩展1:跳台阶
一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
思路:斐波拉契数序列,初始条件n=1:只能一种方法,n=2:两种
对于第n个台阶来说,只能从n-1或者n-2的台阶跳上来,所以
F(n) = F(n-1) + F(n-2)
扩展2:变态跳台阶
题目描述
一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
思路:
因为n级台阶,第一步有n种跳法:跳1级、跳2级、到跳n级
跳1级,剩下n-1级,则剩下跳法是f(n-1)
跳2级,剩下n-2级,则剩下跳法是f(n-2)
所以f(n)=f(n-1)+f(n-2)+…+f(1)
因为f(n-1)=f(n-2)+f(n-3)+…+f(1)
所以f(n)=2*f(n-1)
所以f(n)=2的(n-1)次幂
public class Solution { public int JumpFloorII(int target) { if(target<=0) return 0; return 1<<(target-1); }}
10、二进制中1的个数
题目描述
输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
最差的解法:因为要考虑负数的问题,若是负数,因为要保证一直输负数,多以第一位一直为1,最后会变成0XFFFFFFFF,造成死循环
public class Solution {public int NumberOf1(int n) { int count= 0; int flag = 1; while (n!= 0){ if ((n & 1) != 0){ count++; } n = n>>1; } return count; } }
改进的解法:
public class Solution {public int NumberOf1(int n) { int count= 0; int flag = 1; while (flag != 0){ if ((n & flag) != 0){ count++; } flag = flag << 1; } return count; } }
最精妙的解法:
public class Solution { public int NumberOf1(int n) { int count = 0; while(n!= 0){ count++; n = n & (n - 1); } return count; }}
11、数值的整数次方
题目描述
给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。
思路1:本题主要考虑边界问题,全面不够高效的解法,注意:由于计算机表示小数(包括float和double型小数)都有误差,我们不能直接用==判断两个小数是否相等,如果两个小数的差的绝对值很小,比如小于0.0000001,就可以认为他们相等
public class Solution { public double Power(double base, int exponent) { double res = 0.0; if (equal(base, 0.0) && exponent < 0) { throw new RuntimeException("0的负数次幂没有意义"); } if (exponent == 0) { return 1.0; } if (exponent < 0) { res = powerWithExponent(1.0/base, -exponent); } else { res = powerWithExponent(base, exponent); } return res; } private double powerWithExponent(double base, int exponent) { double res = 1.0; for (int i = 1; i <= exponent; i++) { res = res * base; } return res; } private boolean equal(double num1, double num2) { if (Math.abs(num1 - num2) < 0.0000001) { return true; } return false; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
思路2:n为偶数时:a^n=a^n/2 * a^n/2;
n为奇数,a^n=(a^(n-1)/2)* (a^(n-1/2))* a
所以对乘法处进行优化,如果是32次方,等于16次方*16次方
private double powerWithExponent(double base, int exponent) { if(exponent==0){ return 1; } if(exponent==1){ return base; } double result = powerWithExponent(base,exponent>>1); result*=result; if((exponent & 0x1)==1){ result *= base; } return result; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
12、打印1到最大的n位数
题目描述:如n=3,则从1打印到999
public class Solution { public static void Print1ToMaxOfNDigits(int n) { if (n <= 0) return; char[] number = new char[n]; for (int i = 0; i < n; i++) { number[i] = '0'; } while (!Increment(number)) { PrintNumber(number); } } public static boolean Increment(char[] number) { boolean isOverflow = false; int nTakeOver = 0; int nLength = number.length; for (int i = nLength - 1; i >= 0; i--) { int nSum = number[i] - '0' + nTakeOver; if (i == nLength - 1) nSum++; if (nSum >= 10) { if (i == 0) isOverflow = true; else { nSum -= 10; nTakeOver = 1; number[i] = (char) ('0' + nSum); } } else { number[i] = (char) ('0' + nSum); break; } } return isOverflow; } public static void PrintNumber(char[] number) { boolean isBeginning0 = true; int nLength = number.length; for (int i = 0; i < nLength; ++i) { if (isBeginning0 && number[i] != '0') isBeginning0 = false; if (!isBeginning0) { System.out.print(number[i]); } } System.out.println(); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
思路2:用递归,代码简洁,思路不好想,每一位都是从0到9的全排列
public class Solution { public static void Print1ToMaxOfNDigits(int n) { if (n <= 0) return; char[] number = new char[n]; for (int i = 0; i < 10; ++i) { number[0] = (char) (i + '0'); Print1ToMaxOfNDigitsRecursively(number, n, 0); } } public static void Print1ToMaxOfNDigitsRecursively(char[] number, int length,int index) { if (index == length - 1) { PrintNumber(number); return; } for (int i = 0; i < 10; ++i) { number[index + 1] = (char) (i + '0'); Print1ToMaxOfNDigitsRecursively(number, length, index + 1); } } public static void PrintNumber(char[] number) { boolean isBeginning0 = true; int nLength = number.length; for (int i = 0; i < nLength; ++i) { if (isBeginning0 && number[i] != '0') isBeginning0 = false; if (!isBeginning0) { System.out.print(number[i]); } } System.out.println(); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
13、在O(1)时间删除链表结点
给定单向链表头指针和一个节点指针,在O(1)时间删除链表结点
public void delete(Node head, Node toDelete){ if(toDelete == null){ return ; } if(toDelete.next != null){ toDelete.val = toDelete.next.val; toDelete.next = toDelete.next.next; }else if(head == toDelete){ head = null; }else{ Node node = head; while(node.next != toDelete){ node = node.next; } node.next = null; } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
14、调整数组顺序使奇数位于偶数前面
题目描述
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。
public class Solution { public void reOrderArray(int [] array) { int length = array.length; if(length == 0){ return; } int[] des = new int[length]; MergeMethod(array, des, 0,length - 1); } public void MergeMethod(int[] array, int [] des, int start, int end){ if(start < end){ int mid = (start + end) / 2; MergeMethod(array, des, start, mid); MergeMethod(array, des, mid + 1, end); Merge(array, des, start, mid, end); } } public void Merge(int[] array, int[] des, int start, int mid, int end){ int i = start; int j = mid + 1; int k = start; while(i <= mid && array[i] % 2 == 1){ des[k++] = array[i++]; } while(j <= end && array[j] % 2 == 1){ des[k++] = array[j++]; } while(i <= mid){ des[k++] = array[i++]; } while(j <= end){ des[k++] = array[j++]; } for(int m = start; m <= end; m++){ array[m] = des[m]; } }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
15、链表中倒数第k个结点
题目描述
输入一个链表,输出该链表中倒数第k个结点。
思路:两个指针,先让第一个指针和第二个指针都指向头结点,然后再让第一个指正走(k-1)步,到达第k个节点。然后两个指针同时往后移动,当第一个结点到达末尾的时候,第二个结点所在位置就是倒数第k个节点了
/**public class ListNode { int val; ListNode next = null; ListNode(int val) { this.val = val; }}*/public class Solution { public ListNode FindKthToTail(ListNode head,int k) { if(head==null||k<=0){ return null; } ListNode pre=head; ListNode last=head; for(int i=1;i<k;i++){ if(pre.next!=null){ pre=pre.next; }else{ return null; } } while(pre.next!=null){ pre = pre.next; last=last.next; } return last; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
16、反转链表
题目描述
输入一个链表,反转链表后,输出链表的所有元素。
/* public class ListNode { int val; ListNode next = null; ListNode(int val) { this.val = val; } }*/public class Solution { public ListNode ReverseList(ListNode head) { if (head == null) return null; if (head.next == null) return head; ListNode pPre = null; ListNode p = head; ListNode pNext = head.next; ListNode newHead = null; while (p != null) { pNext = p.next; if (pNext == null) newHead = p; p.next = pPre; pPre = p; p = pNext; } return newHead; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
17、合并两个排序的链表
题目描述
输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
/**public class ListNode { int val; ListNode next = null; ListNode(int val) { this.val = val; }}*/public class Solution { public ListNode Merge(ListNode list1, ListNode list2) { if(list1==null) return list2; else if(list2==null) return list1; ListNode mergeHead=null; if(list1.val<list2.val){ mergeHead=list1; mergeHead.next=Merge(list1.next, list2); } else{ mergeHead=list2; mergeHead.next=Merge(list1, list2.next); } return mergeHead; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
非递归方法:
public class Solution { public ListNode Merge(ListNode list1,ListNode list2) { if(list1==null&&list2==null) return null; if(list1==null&&list2!=null) return list2; if(list1!=null&&list2==null) return list1; ListNode head = null; if(list1.val<list2.val){ head = list1; list1 = list1.next; } else{ head = list2; list2 = list2.next; } ListNode cur = head; cur.next=null; while(list1!=null&&list2!=null){ if(list1.val<list2.val){ cur.next = list1; list1 = list1.next; } else{ cur.next = list2; list2 = list2.next; } cur = cur.next; cur.next = null; } if(list1==null&&list2!=null){ cur.next =list2; }else if(list2==null&&list1!=null){ cur.next = list1; } return head; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
18、树的子结构
题目描述
输入两颗二叉树A,B,判断B是不是A的子结构。
思路:首先遍历A树,找到A的根节点和B的根节点相同的点,找到之后再遍历A和B的各个子节点是否相同
/**public class TreeNode { int val = 0; TreeNode left = null; TreeNode right = null; public TreeNode(int val) { this.val = val; }}*/public class Solution { public boolean HasSubtree(TreeNode root1,TreeNode root2) { if(root2==null) return false; if(root1==null && root2!=null) return false; boolean flag = false; if(root1.val==root2.val){ flag = isSubTree(root1,root2); } if(!flag){ flag = HasSubtree(root1.left, root2); } if(!flag){ flag = HasSubtree(root1.right, root2); } return flag; } private boolean isSubTree(TreeNode root1, TreeNode root2) { if(root2==null) return true; if(root1==null && root2!=null) return false; if(root1.val==root2.val){ return isSubTree(root1.left, root2.left) && isSubTree(root1.right, root2.right); } return false; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
19、二叉树的镜像
题目描述
操作给定的二叉树,将其变换为源二叉树的镜像。
二叉树的镜像定义:源二叉树
8
/ \
6 10
/ \ / \
5 7 9 11
镜像二叉树
8
/ \
10 6
/ \ / \
11 9 7 5
思路1:用栈结构(改成队列结构也可以),将节点依次入栈,每个入栈的节点都镜像他的子节点
/**public class TreeNode { int val = 0; TreeNode left = null; TreeNode right = null; public TreeNode(int val) { this.val = val; }}*/import java.util.Stack;public class Solution { public void Mirror(TreeNode root) { if(root == null){ return; } Stack<TreeNode> stack = new Stack<TreeNode>(); stack.push(root); while(!stack.isEmpty()){ TreeNode node = stack.pop(); if(node.left != null||node.right != null){ TreeNode temp = node.left; node.left = node.right; node.right = temp; } if(node.left!=null){ stack.push(node.left); } if(node.right!=null){ stack.push(node.right); } } }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
思路2:前序遍历的递归
public class Solution { public void Mirror(TreeNode root) { if(root == null) return; if(root.left != null || root.right != null) { TreeNode tempNode = null; tempNode = root.left; root.left = root.right; root.right = tempNode; Mirror(root.left); Mirror(root.right); } }}
20、顺时针打印矩阵
题目描述
输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下矩阵:
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.
import java.util.ArrayList;public class Solution { public ArrayList<Integer> printMatrix(int [][] matrix) { ArrayList<Integer> list = new ArrayList<Integer>(); int rows = matrix.length; int columns = matrix[0].length; if(matrix == null || columns <= 0 || rows <= 0){ return null; } int start = 0; while(columns > start *2 && rows > start * 2){ print1Circle(list,matrix,columns,rows,start); start++; } return list; } public void print1Circle(ArrayList<Integer> list, int[][] matrix,int columns, int rows, int start) { int endX = columns - 1 - start; int endY = rows - 1 - start; for (int i = start; i <= endX; i++) { list.add(matrix[start][i]); } if (start < endY){ for (int i = start+1; i <= endY; i++) { list.add(matrix[i][endX]); } } if (start < endY && start < endX){ for (int i = endX - 1; i >= start; i--) { list.add(matrix[endY][i]); } } if (start < endY -1 && start < endX){ for (int i = endY - 1; i >= start + 1; i--) { list.add(matrix[i][start]); } } }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
21、包含min函数的栈
题目描述
定义栈的数据结构,请在该类型中实现一个能够得到栈最小元素的min函数。
import java.util.Stack; public class Solution { Stack data=new Stack(); Stack min=new Stack(); public void push(int node) { if(min.empty()){ min.push(node); }else{ int top=(int)min.peek(); if(node<top){ min.push(node); }else{ min.push(top); } } data.push(node); } public void pop() { if(!(data.empty())){ data.pop(); min.pop(); } } public int top() { return (int)data.peek(); } public int min() { if(min.empty()){ return 0; } return (int)min.peek(); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
22、栈的压入、弹出序列
题目描述
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。
【思路】借用一个辅助的栈,push序列依次入栈,每次都判断,栈顶元素和pop序列是否相等,相等则弹出栈,不相等,则push序列继续入栈,最后判断栈是否为空
举例:
入栈1,2,3,4,5
出栈4,5,3,2,1
首先1入辅助栈,此时栈顶1≠4,继续入栈2
此时栈顶2≠4,继续入栈3
此时栈顶3≠4,继续入栈4
此时栈顶4=4,出栈4,弹出序列向后一位,此时为5,,辅助栈里面是1,2,3
此时栈顶3≠5,继续入栈5
此时栈顶5=5,出栈5,弹出序列向后一位,此时为3,,辅助栈里面是1,2,3
….
依次执行,最后辅助栈为空。如果不为空说明弹出序列不是该栈的弹出顺序。
import java.util.ArrayList;import java.util.Stack;public class Solution { public boolean IsPopOrder(int [] pushA,int [] popA) { if(pushA.length == 0 || popA.length == 0) return false; Stack<Integer> s = new Stack<Integer>(); int popIndex = 0; for(int i = 0; i< pushA.length;i++){ s.push(pushA[i]); while(!s.empty() &&s.peek() == popA[popIndex]){ s.pop(); popIndex++; } } return s.empty(); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
23、从上往下打印二叉树——层次遍历
题目描述
从上往下打印出二叉树的每个节点,同层节点从左至右打印。
思路:一个队列容器,每次打印节点的时候把此节点的左右子节点加入进去
import java.util.*;/**public class TreeNode { int val = 0; TreeNode left = null; TreeNode right = null; public TreeNode(int val) { this.val = val; }}*/public class Solution { public ArrayList<Integer> PrintFromTopToBottom(TreeNode root) { ArrayList<Integer> list = new ArrayList<Integer>(); if(root==null){ return list; } Queue<TreeNode> queue = new LinkedList<TreeNode>(); queue.offer(root); while (!queue.isEmpty()) { TreeNode treeNode = queue.poll(); if (treeNode.left != null) { queue.offer(treeNode.left); } if (treeNode.right != null) { queue.offer(treeNode.right); } list.add(treeNode.val); } return list; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
24、二叉搜索树的后序遍历序列
题目描述
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。
public class Solution { public static boolean VerifySquenceOfBST(int[] sequence) { if(sequence.length ==0){ return false; } return VerifySquenceOfBST1(sequence,0,sequence.length-1); } public static boolean VerifySquenceOfBST1(int[] sequence,int start,int end) { if(start > end) return true; int root=sequence[end]; int i=0; for(;i<end;i++){ if(sequence[i]>root){ break; } } int j=i; for(;j<end;j++){ if(sequence[j]<root) return false; } boolean left=true; boolean right=true; if(i>start){ left=VerifySquenceOfBST1(sequence,start,i-1); } if(i<sequence.length-1) right=VerifySquenceOfBST1(sequence,i,end-1); return (left&&right); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
25、二叉树中和为某一值的路径
题目描述
输入一颗二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。
import java.util.ArrayList;import java.util.Stack;public class Solution { public ArrayList<ArrayList<Integer>> FindPath(TreeNode root, int target) { ArrayList<ArrayList<Integer>> pathList=new ArrayList<ArrayList<Integer>>(); if(root==null) return pathList; Stack<Integer> stack=new Stack<Integer>(); FindPath(root,target,stack,pathList ); return pathList; } private void FindPath(TreeNode root, int target, Stack<Integer> path, ArrayList<ArrayList<Integer>> pathList) { if(root==null) return; if(root.left==null&&root.right==null){ if(root.val==target){ ArrayList<Integer> list=new ArrayList<Integer>(); for(int i:path){ list.add(new Integer(i)); } list.add(new Integer(root.val)); pathList.add(list); } } else{ path.push(new Integer(root.val)); FindPath(root.left, target-root.val, path, pathList); FindPath(root.right, target-root.val, path, pathList); path.pop(); } }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
26、复杂链表的复制
题目描述
输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点)。
方法一:用hashMap映射原链表,牺牲O(N)空间换来时间
import java.util.HashMap; public class Solution { public RandomListNode Clone(RandomListNode pHead) { if(pHead == null) return null; HashMap<RandomListNode, RandomListNode> map = new HashMap<RandomListNode, RandomListNode>(); RandomListNode newHead = new RandomListNode(pHead.label); RandomListNode pre = pHead, newPre = newHead; map.put(pre, newPre); while(pre.next != null){ newPre.next = new RandomListNode(pre.next.label); pre = pre.next; newPre = newPre.next; map.put(pre, newPre); } pre = pHead; newPre = newHead; while(newPre != null){ newPre.random = map.get(pre.random); pre = pre.next; newPre = newPre.next; } return newHead; } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
方法二:不借用辅助空间
public class Solution { public RandomListNode Clone(RandomListNode pHead){ if(pHead==null) return null; RandomListNode pCur = pHead; while(pCur!=null){ RandomListNode node = new RandomListNode(pCur.label); node.next = pCur.next; pCur.next = node; pCur = node.next; } pCur = pHead; while(pCur!=null){ if(pCur.random!=null) pCur.next.random = pCur.random.next; pCur = pCur.next.next; } RandomListNode head = pHead.next; RandomListNode cur = head; pCur = pHead; while(pCur!=null){ pCur.next = pCur.next.next; if(cur.next!=null) cur.next = cur.next.next; cur = cur.next; pCur = pCur.next; } return head; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
27、二叉搜索树与双向链表
题目描述
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
方法一:递归中序遍历
/**public class TreeNode { int val = 0; TreeNode left = null; TreeNode right = null; public TreeNode(int val) { this.val = val; }}*/public class Solution { TreeNode head = null; TreeNode realHead = null; public TreeNode Convert(TreeNode pRootOfTree) { if(pRootOfTree==null) return null; Convert(pRootOfTree.left); if (head == null) { head = pRootOfTree; realHead = pRootOfTree; } else { head.right = pRootOfTree; pRootOfTree.left = head; head = pRootOfTree; } Convert(pRootOfTree.right); return realHead; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
方法二:
/** 非递归 */import java.util.Stack;public class Solution { public TreeNode Convert(TreeNode pRootOfTree) { if(pRootOfTree == null) return pRootOfTree; TreeNode list = null; Stack<TreeNode> s = new Stack<>(); while(pRootOfTree != null || !s.isEmpty()){ if(pRootOfTree != null) { s.push(pRootOfTree); pRootOfTree = pRootOfTree.right; } else { pRootOfTree = s.pop(); if(list == null) list = pRootOfTree; else { list.left = pRootOfTree; pRootOfTree.right = list; list = pRootOfTree; } pRootOfTree = pRootOfTree.left; } } return list; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
28、字符串的排列
题目描述
输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。 结果请按字母顺序输出。
扩展:求字符串的全组合
如:abc,全组合为:a,b,c,ab,ac,bc,abc
public final class PermutationCombinationHolder { public static void combination(char[] chars) { char[] subchars = new char[chars.length]; for (int i = 0; i < chars.length; ++i) { final int m = i + 1; combination(chars, chars.length, m, subchars, m); } } public static void combination(char[] chars, int n, int m, char[] subchars, int subn) { if (m == 0) { for (int i = 0; i < subn; ++i) { System.out.print(subchars[i]); } System.out.println(); } else { for (int i = n; i >= m; --i) { subchars[m - 1] = chars[i - 1]; combination(chars, i - 1, m - 1, subchars, subn); } } } public static void permutation(char[] chars) { permutation(chars, 0, chars.length - 1); } public static void permutation(char[] chars, int begin, int end) { if (begin == end) { for (int i = 0; i < chars.length; ++i) { System.out.print(chars[i]); } System.out.println(); } else { for (int i = begin; i <= end; ++i) { if (canSwap(chars, begin, i)) { swap(chars, begin, i); permutation(chars, begin + 1, end); swap(chars, begin, i); } } } } public static void swap(char[] chars, int from, int to) { char temp = chars[from]; chars[from] = chars[to]; chars[to] = temp; } public static boolean canSwap(char[] chars, int begin, int end) { for (int i = begin; i < end; ++i) { if (chars[i] == chars[end]) { return false; } } return true; } public static void main(String[] args) { final char[] chars = new char[] {'a', 'b', 'c'}; permutation(chars); System.out.println("==================="); combination(chars); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
方法二:DFS
import java.util.*;public class Solution { private char [] seqs; private Integer [] book; private HashSet<String> result = new HashSet<String>(); /** * 输入一个字符串,按字典序打印出该字符串中字符的所有排列。 * 例如输入字符串abc,则打印出由字符a,b,c * 所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。 结果请按字母顺序输出。 输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。\ * @param str * @return */ public ArrayList<String> Permutation(String str) { ArrayList<String> arrange = new ArrayList<String>(); if(str == null || str.isEmpty()) return arrange; char[] strs = str.toCharArray(); seqs = new char[strs.length]; book = new Integer[strs.length]; for (int i = 0; i < book.length; i++) { book[i] = 0; } dfs(strs, 0); arrange.addAll(result); Collections.sort(arrange); return arrange; } /** * 深度遍历法 */ private void dfs(char[] arrs, int step){ if(arrs.length == step){ String str = ""; for (int i = 0; i < seqs.length; i++) { str += seqs[i]; } result.add(str); return; } for (int i = 0; i < arrs.length; i++) { if(book[i] == 0){ seqs[step] = arrs[i]; book[i] = 1; dfs(arrs, step + 1); book[i] = 0; } } }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
方法三:字典序算法
import java.util.*;//步骤如下://1.从这个序列中从右至左找第一个左邻小于右邻的字符,记录下标为index1 ,如果找不到,说明求解完成。//2.从这个序列中从右至左找第一个大于str[index1]的字符,记录下标为index2//3.交换index1和index2的字符,对index1+1后的所有字符进行升序排序,此时得到的即为str按字典序的下一个排列//4. 重复1~3的步骤,直到全部找完 public class Solution { public ArrayList<String> Permutation(String str) { ArrayList<String> res = new ArrayList<>(); if (str != null && str.length() > 0) { char[] seq = str.toCharArray(); Arrays.sort(seq); //排列 res.add(String.valueOf(seq)); //先输出一个解 int len = seq.length; while (true) { int p = len - 1, q; //从后向前找一个seq[p - 1] < seq[p] while (p >= 1 && seq[p - 1] >= seq[p]) --p; if (p == 0) break; //已经是“最小”的排列,退出 //从p向后找最后一个比seq[p]大的数 q = p; --p; while (q < len && seq[q] > seq[p]) q++; --q; //交换这两个位置上的值 swap(seq, q, p); //将p之后的序列倒序排列 reverse(seq, p + 1); res.add(String.valueOf(seq)); } } return res; } public static void reverse(char[] seq, int start) { int len; if(seq == null || (len = seq.length) <= start) return; for (int i = 0; i < ((len - start) >> 1); i++) { int p = start + i, q = len - 1 - i; if (p != q) swap(seq, p, q); } } public static void swap(char[] cs, int i, int j) { char temp = cs[i]; cs[i] = cs[j]; cs[j] = temp; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
29、数组中出现次数超过一半的数字
题目描述
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
思路:O(n)的思想是,定义两个变量result 和count,每次循环时,如果array[i]的值等于result ,则count自增,如不等并且count>0,则count自减,count==0,重新对temp赋值为当前array[i],count赋值为1。
如存在大于一半的数,直接返回result 就是了,但测试数据中有不存在的情况,所以最后又来了一遍校验,检查当前result 值是否出现过一半以上。
public class Solution { public int MoreThanHalfNum_Solution(int [] array) { if(array==null || array.length <= 0){ return 0; } int result = array[0]; int count = 1; for (int i = 1; i < array.length; i++) { if (array[i] == result) { count++; } else if (count > 0 ) { count--; } else if(count == 0){ result = array[i]; count = 1; } } count=0; for(int i=0;i<array.length;i++){ if(array[i]==result) count++; } return count > array.length/2 ? result : 0; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
30、最小的K个数
题目描述
输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。
思路1:
经典常用的算法,快速排序的精髓利用快速排序划分的思想,每一次划分就会有一个数字位于以数组从小到达排列的的最终位置index;
位于index左边的数字都小于index对应的值,右边都大于index指向的值;
所以,当index > k-1时,表示k个最小数字一定在index的左边,此时,只需要对index的左边进行划分即可;
当index < k - 1时,说明index及index左边数字还没能满足k个数字,需要继续对k右边进行划分;
import java.util.ArrayList;public class Solution { public ArrayList GetLeastNumbers_Solution(int [] input, int k) { ArrayList aList = new ArrayList(); if(input.length == 0 || k > input.length || k <= 0) return aList; int low = 0; int high = input.length-1; int index = Partition(input,k,low,high); while(index != k-1){ if (index > k-1) { high = index-1; index = Partition(input,k,low,high); }else{ low = index+1; index = Partition(input,k,low,high); } } for (int i = 0; i < k; i++) aList.add(input[i]); return aList; } public int Partition(int[] input,int k,int low,int high){ int pivotkey = input[k-1]; swap(input,k-1,low); while(low < high){ while(low < high && input[high] >= pivotkey) high--; swap(input,low,high); while(low < high && input[low] <= pivotkey) low++; swap(input,low,high); } return low; } private void swap(int[] input, int low, int high) { int temp = input[high]; input[high] = input[low]; input[low] = temp; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
思路2
-对于这个容器的实现,我们可以使用最大堆的数据结构,最大堆中,根节点的值大于它的子树中的任意节点值。Java中的TreeSet类实现了红黑树的功能,它底层是通过TreeMap实现的,TreeSet中的数据会按照插入数据自动升序排列(按自然顺序)。因此我们直接将数据依次放入到TreeSet中,数组就会自动排序。
public static ArrayList<Integer> GetLeastNumbers_Solution(int[] input, int k) { ArrayList<Integer> leastNum = new ArrayList<Integer>(); if (input == null || input.length < 1 || k < 1 || k > input.length) return leastNum; TreeSet<Integer> kSet = new TreeSet<Integer>(); for (int i = 0; i < input.length; i++) { if (kSet.size() < k) { kSet.add(input[i]); } else { if (input[i] < kSet.last()) { kSet.remove(kSet.last()); kSet.add(input[i]); } } } Iterator<Integer> it = kSet.iterator(); while (it.hasNext()) { leastNum.add(it.next()); } return leastNum; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
31、连续子数组的最大和
题目描述:
输入一个整型数组,数组里有正数和负数,数组中一个或者多个连续的数字组成一个子数组,求所有子数组的最大值,要求时间复杂度为O(N)
思路1:
public class Solution { public int FindGreatestSumOfSubArray(int[] array) { if(array.length==0) return 0; else{ int total=array[0],maxSum=array[0]; for(int i=1;i<array.length;i++){ if(total>=0) total+=array[i]; else total=array[i]; if(total>maxSum) maxSum=total; } return maxSum; } }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
思路2:动态规划(相当重点)
public class Solution { public int FindGreatestSumOfSubArray(int[] array) { if(array.length == 0) return 0; int result = Integer_MinValue; int sum = 0; for(int i = 0; i < array.length; ++i) { sum = max(array[i], sum + array[i]); result = max(result, sum); } return result; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
32、整数中1出现的次数(从1到n整数中1出现的次数)
题目描述
例如n=13的整数中1出现的次数,1~13中包含1的数字有1、10、11、12、13因此共出现6次
思路:
一、1的数目
编程之美上给出的规律:
1、 如果第i位(自右至左,从1开始标号)上的数字为0,则第i位可能出现1的次数由更高位决定(若没有高位,视高位为0),等于更高位数字 * 当前位数的权重10^(i-1)。
2、如果第i位上的数字为1,则第i位上可能出现1的次数不仅受更高位影响,还受低位影响(若没有低位,视低位为0),等于更高位数字 * 当前位数的权重10^(i-1)+(低位数字+1)。
3、如果第i位上的数字大于1,则第i位上可能出现1的次数仅由更高位决定(若没有高位,视高位为0),等于(更高位数字+1) * 当前位数的权重10^(i-1)。
二、X的数目
这里的 X∈[1,9] ,因为 X=0 不符合下列规律,需要单独计算。
首先要知道以下的规律:
从 1 至 10,在它们的个位数中,任意的 X 都出现了 1 次。
从 1 至 100,在它们的十位数中,任意的 X 都出现了 10 次。
从 1 至 1000,在它们的百位数中,任意的 X 都出现了 100 次。
依此类推,从 1 至 10^ i ,在它们的左数第二位(右数第 i 位)中,任意的 X 都出现了 10^(i-1) 次。
这个规律很容易验证,这里不再多做说明。
接下来以 n=2593,X=5 为例来解释如何得到数学公式。从 1 至 2593 中,数字 5 总计出现了 813 次,其中有 259 次出现在个位,260 次出现在十位,294 次出现在百位,0 次出现在千位。
现在依次分析这些数据,
首先是个位。从 1 至 2590 中,包含了 259 个 10,因此任意的 X 都出现了 259 次。最后剩余的三个数 2591, 2592 和 2593,因为它们最大的个位数字 3 < X,因此不会包含任何 5。(也可以这么看,3 < X,则个位上可能出现的X的次数仅由更高位决定,等于更高位数字(259)*10^(1-1)=259)。
然后是十位。从 1 至 2500 中,包含了 25 个 100,因此任意的 X 都出现了 25×10=250 次。剩下的数字是从 2501 至 2593,它们最大的十位数字 9 > X,因此会包含全部 10 个 5。最后总计 250 + 10 = 260。(也可以这么看,9>X,则十位上可能出现的X的次数仅由更高位决定,等于更高位数字(25+1)*10^(2-1)=260)。
接下来是百位。从 1 至 2000 中,包含了 2 个 1000,因此任意的 X 都出现了 2×100=200 次。剩下的数字是从 2001 至 2593,它们最大的百位数字 5 == X,这时情况就略微复杂,它们的百位肯定是包含 5 的,但不会包含全部 100 个。如果把百位是 5 的数字列出来,是从 2500 至 2593,数字的个数与百位和十位数字相关,是 93+1 = 94。最后总计 200 + 94 = 294。(也可以这么看,5==X,则百位上可能出现X的次数不仅受更高位影响,还受低位影响,等于更高位数字(2)*10^(3-1)+(93+1)=294)。
最后是千位。现在已经没有更高位,因此直接看最大的千位数字2< X,所以不会包含任何 5。(也可以这么看,2< X,则千位上可能出现的X的次数仅由更高位决定,等于更高位数字(0)*10^(4-1)=0)。
到此为止,已经计算出全部数字 5 的出现次数。
总结一下以上的算法,可以看到,当计算右数第 i 位包含的 X 的个数时:
- 1、取第 i 位左边的数字(高位),乘以 10 ^(i−1) ,得到基础值 a 。
- 2、取第 i 位数字,计算修正值:
- 1、如果大于 X,则结果为 a+ 10 ^(i−1) 。
- 2、如果小于 X,则结果为 a 。
- 3、如果等 X,则取第 i 位右边(低位)数字,设为 b ,最后结果为 a+b+1 。
相应的代码非常简单,效率也非常高,时间复杂度只有 O( log 10 n) 。
public class Solution { public int NumberOf1Between1AndN_Solution(int n) { return NumberOfXBetween1AndN_Solution1(n,1); } /** * @param n * @param x [1,9] * @return (从1到n整数中x出现的次数) */ public int NumberOfXBetween1AndN_Solution1(int n,int x) { if(n<0||x<1||x>9) return 0; int high,low,curr,tmp,i = 1; high = n; int total = 0; while(high!=0){ high = n/(int)Math.pow(10, i); tmp = n%(int)Math.pow(10, i); curr = tmp/(int)Math.pow(10, i-1); low = tmp%(int)Math.pow(10, i-1); if(curr==x){ total+= high*(int)Math.pow(10, i-1)+low+1; }else if(curr<x){ total+=high*(int)Math.pow(10, i-1); }else{ total+=(high+1)*(int)Math.pow(10, i-1); } i++; } return total; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
33、把数组排成最小的数
题目描述:
输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。
package cn.zhuang.offer;import java.util.ArrayList;import java.util.Arrays;import java.util.Comparator;public class Main { public static String PrintMinNumber(int [] numbers) { if(numbers == null || numbers.length == 0) return ""; int len = numbers.length; String[] str = new String[len]; StringBuilder sb = new StringBuilder(); for(int i = 0; i < len; i++){ str[i] = String.valueOf(numbers[i]); } Arrays.sort(str,new Comparator<String>(){ @Override public int compare(String s1, String s2) { String c1 = s1 + s2; String c2 = s2 + s1; return c1.compareTo(c2); } }); for(int i = 0; i < len; i++){ sb.append(str[i]); } return sb.toString(); } public static void main(String[] args){ int[] a = {3,32,421}; System.out.println(PrintMinNumber(a)); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
java中的compareto方法,返回参与比较的前后两个字符串的asc码的差值,看下面一组代码
String a=”a”,b=”b”;
System.out.println(a.compareto.b);
则输出-1;
若a=”a”,b=”a”则输出0;
若a=”b”,b=”a”则输出1;
单个字符这样比较,若字符串比较长呢??
若a=”ab”,b=”b”,则输出-1;
若a=”abcdef”,b=”b”则输出-1;
也就是说,如果两个字符串首字母不同,则该方法返回首字母的asc码的差值;
如果首字母相同呢??
若a=”ab”,b=”a”,输出1;
若a=”abcdef”,b=”a”输出5;
若a=”abcdef”,b=”abc”输出3;
若a=”abcdef”,b=”ace”输出-1;
即参与比较的两个字符串如果首字符相同,则比较下一个字符,直到有不同的为止,返回该不同的字符的asc码差值,如果两个字符串不一样长,可以参与比较的字符又完全一样,则返回两个字符串的长度差值
34、丑数
题目描述:
把只包含因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含因子7。习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。
思路1:最简单的方法就是先通过将一个数不断除以2,3,5来判定该数是不是丑数,而后在从1开始,依次往后判断每个数是不是丑数,并记下丑数的个数,这样当计算的个数为给定值时,便是需要求的第n个丑数,这种方法的时间复杂度为O(k),这里的k为第n个丑数的大小,比如第1500个丑数的大小为859963392,那么就需要判断859963392次,时间效率非常低。
public boolean IsUgly(int number){ while(number % 2 == 0) number /= 2; while(number % 3 == 0) number /= 3; while(number % 5 == 0) number /= 5; return (number == 1) ? true : false;}public int GetUglyNumber(int index){ if(index <= 0) return 0; int number = 0; int uglyFound = 0; while(uglyFound < index) { ++number; if(IsUgly(number)) { ++uglyFound; } } return number;}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
思路Better2:直观的优化措施就是看能不能将时间复杂度降低到O(n),即只在丑数上花时间,而不在非丑数上浪费时间。剑指offer上给的思路很好,用O(n)的辅助空间来得到O(n)的时间复杂度。其核心思想是:每一个丑数必然是由之前的某个丑数与2,3或5的乘积得到的,这样下一个丑数就用之前的丑数分别乘以2,3,5,找出这三这种最小的并且大于当前最大丑数的值,即为下一个要求的丑数。
import java.util.*;public class Solution{ public int GetUglyNumber_Solution(int n) { if(n==0)return 0; ArrayList<Integer> res=new ArrayList<Integer>(); res.add(1); int i2=0,i3=0,i5=0; while(res.size()<n) { int m2=res.get(i2)*2; int m3=res.get(i3)*3; int m5=res.get(i5)*5; int min=Math.min(m2,Math.min(m3,m5)); res.add(min); if(min==m2)i2++; if(min==m3)i3++; if(min==m5)i5++; } return res.get(res.size()-1); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
35、第一个只出现一次的字符
描述:在一个字符串(1<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符的位置。若为空串,返回-1。位置索引从0开始,如“abaccdrff”,则输出“b”
第一种,数组方法:
public class Solution { public int FirstNotRepeatingChar(String str) { if (str.length() == 0) { return -1; } char c = 'A'; if(str.charAt(0) >= 'a'){ c = 'a'; } int[] counts = new int[26]; for (int i = 0; i < str.length(); i++) { counts[str.charAt(i) - c]++; } for (int i = 0; i < str.length(); i++) { if (counts[str.charAt(i) - c] == 1){ return i; } } return -1; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
第二种,HashMap方法:
import java.util.LinkedHashMap;public class Solution { public int FirstNotRepeatingChar(String str) { LinkedHashMap <Character, Integer> map = new LinkedHashMap<Character, Integer>(); for(int i=0;i<str.length();i++){ if(map.containsKey(str.charAt(i))){ int time = map.get(str.charAt(i)); map.put(str.charAt(i), ++time); } else { map.put(str.charAt(i), 1); } } int pos = -1; int i=0; for(;i<str.length();i++){ char c = str.charAt(i); if (map.get(c) == 1) { return i; } } return pos; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
36、数组中的逆序对
题目描述:
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
{7,5,6,4},则76,75,74,64,65,一共5个
思路:
public class Solution { private int reversePair = 0; public int InversePairs(int [] array) { if(array==null) return 0; int len = array.length; if(len==0) return 0; sort(array,0,len-1); return reversePair; } private void sort(int[]arr,int start,int end){ if(start<end){ int mid = start+(end-start)/2; sort(arr,start,mid); sort(arr,mid+1,end); merger(arr,start,mid,mid+1,end); } } private void merger(int[] arr, int start1, int end1, int start2, int end2) { int len= end2-start1+1; int[] anx = new int[len]; int k = end2-start1+1; int i = end1; int j= end2; while(i>=start1&j>=start2){ if(arr[i]>arr[j]){ anx[--k]=arr[i]; i--; reversePair = reversePair+(j-start2+1); } else{ anx[--k]=arr[j]; j--; } } for(;i>=start1;i--) anx[--k]=arr[i]; for(;j>=start2;j--) anx[--k]=arr[j]; for(int m=0;m<len;m++) arr[start1++]=anx[m]; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
37、两个链表的第一个公共交点
/*public class ListNode { int val; ListNode next = null; ListNode(int val) { this.val = val; }}*/public class Solution { public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) { if (pHead1 == null||pHead2 == null) { return null; } int count1 = 0; ListNode p1 = pHead1; while (p1!=null){ p1 = p1.next; count1++; } int count2 = 0; ListNode p2 = pHead2; while (p2!=null){ p2 = p2.next; count2++; } int flag = count1 - count2; if (flag > 0){ while (flag>0){ pHead1 = pHead1.next; flag --; } while (pHead1!=pHead2){ pHead1 = pHead1.next; pHead2 = pHead2.next; } return pHead1; } if (flag <= 0){ while (flag<0){ pHead2 = pHead2.next; flag ++; } while (pHead1 != pHead2){ pHead2 = pHead2.next; pHead1 = pHead1.next; } return pHead1; } return null; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
38、数字在排序数组中出现的次数
思路:重点是有序数组这个条件,采用二分查找法,分别找到第一个和最后一个,这样无论最好最坏复杂度都是O(lgN)
public class Solution { public int GetNumberOfK(int [] array , int k) { int num = 0; if (array != null && array.length > 0) { int firstKIndex = getFirstK(array, k, 0, array.length - 1); int lastKIndex = getLastK(array, k, 0, array.length - 1); if (firstKIndex > -1 && lastKIndex > -1) num = lastKIndex - firstKIndex + 1; } return num; } public int getFirstK(int[] array, int k, int start, int end) { if (start > end) return -1; int middleIndex = start + (end - start) / 2; int middleData = array[middleIndex]; if (middleData == k) { if (middleIndex > 0 && array[middleIndex - 1] != k || middleIndex == 0) { return middleIndex; } else end = middleIndex - 1; } else if (middleData > k) { end = middleIndex - 1; } else start = middleIndex + 1; return getFirstK(array, k, start, end); } public int getLastK(int array[], int k, int start, int end) { if (start > end) { return -1; } int middleIndex = (start + end) / 2; int middleData = array[middleIndex]; if (middleData == k) { if (middleIndex < array.length - 1 && array[middleIndex + 1] != k || middleIndex == array.length - 1) return middleIndex; else start = middleIndex + 1; } else if (middleData < k) { start = middleIndex + 1; } else end = middleIndex - 1; return getLastK(array, k, start, end); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
39、二叉树的深度
题目描述:
输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。
思路:递归,下一层根节点到上一层根节点,深度加1,判断左子树和右子树的最大值,然后+1
public class Solution { public int getHeight(TreeNode root) { if (root == null) return 0; return max(getHeight(root.left), getHeight(root.right)) + 1; } private int max(int a, int b) { return (a > b) ? a : b; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
扩展题:判断二叉树平衡
描述:如果某二叉树中任意节点的左右子树的深度相差不超过1,那么它就是一棵平衡二叉树。
第一种思路:简洁,但是效率不高,因为会重复遍历子节点
public class Solution { public boolean IsBalanced(TreeNode root) { if (root == null) return true; if (Math.abs(getHeight(root.left) - getHeight(root.right)) > 1) return false; return IsBalanced(root.left) && IsBalanced(root.right); } public int getHeight(TreeNode root) { if (root == null) return 0; return max(getHeight(root.left), getHeight(root.right)) + 1; } private int max(int a, int b) { return (a > b) ? a : b; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
第二种Better思路:从底向上判断,这样可以记录下一层的深度
public class Solution { public boolean IsBalanced(TreeNode root) { int depth = 0; return IsBalanced(root, depth); } public boolean IsBalanced(TreeNode root, int depth) { if (root == null) { depth = 0; return true; } int left = 0, right = 0; if (IsBalanced(root.left, left) && IsBalanced(root.right, right)) { int diff = left - right; if (diff <= 1 && diff >= -1) { depth = 1 + (left > right ? left : right); return true; } } return false; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
40-数组只指出现一次的数字:
异或去重:
适应情景:数组中只有一个数字出现了奇数次,其他的都出现了偶数次。或者只有一个数字出现了偶数次,其他的都出现了奇数次
性质:对于任意的a:a^a=0,a^0=a,a^(-1)=~a。
下面来看三道题目:
1、1-1000放在含有1001个元素的数组中,只有唯一的一个元素值重复,其它均只出现一次。每个数组元素只能访问一次,设计一个算法,将它找出来;不用辅助存储空间,能否设计一个算法实现?
当然,这道题,可以用最直观的方法来做,将所有的数加起来,减去1+2+3+…+1000的和,得到的即是重复的那个数,该方法很容易理解,而且效率很高,也不需要辅助空间,唯一的不足时,如果范围不是1000,而是更大的数字,可能会发生溢出。
我们考虑用异或操作来解决该问题。现在问题是要求重复的那个数字,我们姑且假设该数字式n吧,如果我们能想办法把1-1000中除n以外的数字全部异或两次,而数字n只异或一次,就可以把1-1000中出n以外的所有数字消去,这样就只剩下n了。我们首先把所有的数字异或,记为T,可以得到如下:
T = 1^2^3^4…^n…^n…^1000 = 1^2^3…^1000(结果中不含n)
而后我们再让T与1-1000之间的所有数字(仅包含一个n)异或,便可得到该重复数字n。如下所示:
T^(a^2^3^4…^n…^1000) = T^(T^n) = 0^n = n
2、一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
样例输入:2 4 3 6 3 2 5 5
样例输出:4 6
思路:异或去重是知道如果只有一个只出现一次的数字的求法,但这里是有两个只出现一次的数字,我们便要想办法把他分为两个子数组,每个子数组中包含一个只出现一次的数字,其他的数字都出现了两次。
首先依然从头到尾异或所有的数字,如ABCCDDEEFF,这样得到的结果就是AB异或的结果,那么在异或后的结果中找出其二进制中最右边为1的位,该位既然为1,说明AB对应的该位肯定不同,必定一个为1,一个为0,因此我们可以考虑根据此位是否为1来划分这两个子数组,这样两个只出现一次的数字就分开了
但我们还要保证出现两次的数字都分到同一个子数组中,很明显,相同的数字相同的位上的值是相同的,要么都为1,要么都为0,因此我们同样可以通过判断该位是否为1来将这些出现两次的数字划分到同一个子数组中,该位如果为1,就分到一个子数组中,如果为0,就分到另一个子数组中。
这样就能保证每个子数组中只有一个出现一次的数字,其他的数字都出现两次,分别全部异或即可得到这两个只出现一次的数字。时间复杂度为O(n)。
另外,所有元素异或后,在找出最右边为1的时,****X&(-X)之后得到的数字,是把X中最右边的1保留下来
注意,这里的-X是X的相反数,-X是对X所有位取反+1
package cn.zhuang.offer;public class Main { public static void FindNumsAppearOnce(int[] arr) { int len = arr.length; if(len<2) return; int i; int AllXOR = 0; for(i=0;i<len;i++) AllXOR ^= arr[i]; int res = FindFirstBit1(AllXOR); int num1=0, num2 = 0; for(i=0;i<len;i++) { if(IsBit1(arr[i],res)) num1 ^= arr[i]; else num2 ^= arr[i]; } System.out.println(num1+"and"+num2); } public static int FindFirstBit1(int num) { return num & (-num); } public static boolean IsBit1(int data,int res) { return ((data & res)==0) ? false:true; } public static void main(String[] args) { int[] a = { 1,1,2,2,3,44,55,55,66,66,34,34,5,5,7,7 }; FindNumsAppearOnce(a); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
3、题目:一个int数组中有三个数字a、b、c只出现一次,其他数字都出现了两次。请找出三个只出现一次的数字。
通用性的方法,对于2个,3个出现一次的数字这类的问题,都可以按照该思路去求解,只是时间复杂度可能要稍微大些,为O(8* sizeof(int)* N),8位* 4字节* N自然就是数组的长度了。
该方法的思路如下:
首先由于有3个数字出现一次,其他的都出现两次,所以N肯定为奇数,该方法通过扫描整数的每一位来逐个判断。
再看这3个只出现一次的数字,他们的bit位肯定不可能全部相同,至少有一个位,要么110,要么001,我们可以通过扫面int的所有bit位,扫描每个bit位的时候,遍历数组,首先找到一个,另外的两个就可以按照上题的解法。
如何找到第一个数?
我们遍历数组,分别统计该数组元素中该bit位为1和0的元素个数,分别设为count1和count0,并同时将所有该bit位为1的元素异或结果为temp1,所有该bit位为0的元素异或,得到的结果为temp0。
如果111或000这两种状态,肯定三个都在count为奇数的里边,不好区分,主要找110或001的区分
先看第一种情况,001,如果count1为奇数,则为111或001,则在count1的数组里,如果temp0==0,则为111,此位不是判断的位,下一位,如果temp0==1,则为001,temp1则为所求。
先看第二种情况,110,如果count1为偶数,则为110或000,则在count1的数组里,如果temp1==0,则为000,此位不是判断的位,下一位,如果temp1==1,则为110,temp0则为所求。
说白了,就是看count1为奇数时,temp0是否为1,count1为偶数时,temp1是否为1。
package cn.zhuang.offer;public class Main { public static void FindThreeNumsAppearOnce(int[] arr, int len) { if (len < 3) return; int num1 = FindOneNumAppearOnce(arr, len); System.out.println(num1); int i; for (i = 0; i < len; i++){ if (num1 == arr[i]){ int temp ; temp = arr[i]; arr[i] = arr[len -1]; arr[len - 1]=temp; break; } } FindTwoNumsAppearOnce(arr, len - 1); } public static int FindOneNumAppearOnce(int[] arr, int len) { int count1 = 0; int count0 = 0; int temp1 = 0; int temp0 = 0; int i, j; for (i = 0; i < 32; i++) { count1 = count0 = temp1 = temp0 = 0; for (j = 0; j < len; j++) { if ((arr[j] & (1 << i)) != 0) { temp1 ^= arr[j]; count1++; } else { temp0 ^= arr[j]; count0++; } } if ((temp1 & 1) != 0) { if (temp0 == 0) continue; else return temp1; } else { if (temp1 == 0) continue; else return temp0; } } return Integer.MAX_VALUE; } public static void FindTwoNumsAppearOnce(int[] arr, int len) { int i; int AllXOR = 0; for (i = 0; i < len; i++) AllXOR ^= arr[i]; int res = FindFirstBit1(AllXOR); int num1 = 0; int num2 = 0; for (i = 0; i < len; i++) { if (IsBit1(arr[i], res)) num1 ^= arr[i]; else num2 ^= arr[i]; } System.out.println(num1); System.out.println(num2); } public static int FindFirstBit1(int num) { return num & (-num); } public static boolean IsBit1(int data, int res) { return ((data & res) == 0) ? false : true; } public static void main(String[] args) { int[] a = { 1,2,2,3,44,55,55,66,66,34,34,5,5,7,7 }; FindThreeNumsAppearOnce(a, a.length); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
41、和为S的两个数字
题目描述
输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,任意输出一对。
输入数组{1,2,4,7,11,15}和15,输出4,11
import java.util.ArrayList;public class Solution { public ArrayList<Integer> FindNumbersWithSum(int [] array,int sum) { ArrayList<Integer> list = new ArrayList<Integer>(); if (array == null || array.length < 2) { return list; } int i=0,j=array.length-1; while(i<j){ if(array[i]+array[j]==sum){ list.add(array[i]); list.add(array[j]); return list; }else if(array[i]+array[j]>sum){ j--; }else{ i++; } } return list; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
扩展题:和为S的连续正数序列
描述:输出所有和为S的连续正数序列。序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序
import java.util.ArrayList;public class Solution { public static ArrayList<ArrayList<Integer>> FindContinuousSequence(int sum) { ArrayList<ArrayList<Integer>> list = new ArrayList<ArrayList<Integer>>(); if (sum < 3) return list; ArrayList<Integer> l = new ArrayList<Integer>(); int small = 2; int middle = (1 + sum) / 2; l.add(1); l.add(2); int s = 3; if (s == sum) { list.add(new ArrayList<Integer>(l)); } while (small <= middle) { small++; s += small; l.add(small); if (s == sum) { list.add(new ArrayList<Integer>(l)); } while (s > sum && small <= middle) { s -= l.remove(0); if (s == sum) { list.add(new ArrayList<Integer>(l)); } } } return list; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
42、反转单词
描述:反转英文单词,例如,“student. a am I”反转成“I am a student.”
思想:就是先翻转所有字符,再逐个单词翻转
public class Solution { public String ReverseSentence(String str) { if(str==null||str.trim().equals("")) return str; String[] words = str.split(" "); StringBuffer buffer = new StringBuffer(); for(int i=0;i<words.length;i++){ buffer.append(reverse1(words[i].toCharArray(), 0, words[i].length()-1)).append(" "); } if(buffer.length()>0) buffer.deleteCharAt(buffer.length()-1); return reverse1(buffer.toString().toCharArray(), 0, buffer.length()-1); } private String reverse1(char[] str, int l, int r) { if(l>r) return ""; char tmp; while(l<r){ tmp = str[l]; str[l] = str[r]; str[r] = tmp; l++; r--; } return String.valueOf(str); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
扩展题:字符串左移n位,abcde,左移2位,cdeab
思路:前n位反转,后几位反转,最后总的反转
public class Solution { public String LeftRotateString(String str,int n) { char[] chars = str.toCharArray(); if(chars.length < n) return ""; reverse(chars, 0, n-1); reverse(chars, n, chars.length-1); reverse(chars, 0, chars.length-1); StringBuilder sb = new StringBuilder(chars.length); for(char c:chars){ sb.append(c); } return sb.toString(); } public void reverse(char[] chars,int low,int high){ char temp; while(low<high){ temp = chars[low]; chars[low] = chars[high]; chars[high] = temp; low++; high--; } }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
44、扑克牌的顺序
从扑克牌中抽取5张牌,判断是否连续,大小王是任意数字
思路:选取5张牌,首先去0,然后进行排序,最大值减最小值是否小于等于4,大于4,为false,
然后相邻相减应该大于0小于5,否的为false
import java.util.ArrayList;import java.util.Collections;public class Solution { public boolean isContinuous(int [] numbers) { if(numbers == null || numbers.length == 0 || numbers.length > 5){ return false; } ArrayList<Integer> al = new ArrayList<>(); int len = numbers.length; int count = 0; for(int i = 0; i < len; i++){ if(0 == numbers[i]){ count++; }else{ al.add(numbers[i]); } } Collections.sort(al); int len1 = al.size(); if(Math.abs(al.get(0) - al.get(len1 - 1)) > 4){ return false; } for(int i = 0; i < len1 - 1; i++){ int temp = al.get(i + 1) - al.get(i); if(0 < temp && temp < 5){ continue; }else{ return false; } } return true; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
45、约瑟夫环问题:圆圈中最后一个数字
题目描述:一个环,每次删除第m个数字,求最后一个数字,如0,1,2,3,4这5个数字,从0开始每次删除第3个数字,则依次删除2,0,4,1,最后一个数字是3
第一种解法:数组O(m*N)
public class Solution { public int LastRemaining_Solution(int n, int m) { if(n<1||m<1) return -1; int[] array = new int[n]; int i = -1,step = 0, count = n; while(count>0){ i++; if(i>=n) i=0; if(array[i] == -1) continue; step++; if(step==m) { array[i]=-1; step = 0; count--; } } return i; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
第二种:链表,O(N)
import java.util.*;public class Solution { public int LastRemaining_Solution(int n, int m) { if (m == 0 || n == 0) { return -1; } ArrayList<Integer> data = new ArrayList<Integer>(); for (int i = 0; i < n; i++) { data.add(i); } int index = -1; while (data.size() > 1) { index = (index + m) % data.size(); data.remove(index); index--; } return data.get(0); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
第三种better解法:约瑟夫经典解法,O(N),空间复杂度O(1)
public class Solution { public int LastRemaining_Solution(int n,int m) { if(n==0) return -1; int s=0; for(int i=2;i<=n;i++){ s=(s+m)%i; } return s; }}
46、求1+2+3+…+n
题目描述:求1+2+3+…+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
public class Solution { public int Sum_Solution(int n) { int result = 0; int a = 1; boolean value = ((n!=0) && a == (result = Sum_Solution(n-1))); result += n; return result; }}
47、不用加减乘除做加法
题目描述
写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。
思路:首先看十进制是如何做的: 5+7=12,三步走
第一步:相加各位的值,不算进位,得到2。
第二步:计算进位值,得到10. 如果这一步的进位值为0,那么第一步得到的值就是最终结果。
第三步:重复上述两步,只是相加的值变成上述两步的得到的结果2和10,得到12。
同样我们可以用三步走的方式计算二进制值相加: 5-101,7-111 第一步:相加各位的值,不算进位,得到010,二进制每位相加就相当于各位做异或操作,101^111。
第二步:计算进位值,得到1010,相当于各位做与操作得到101,再向左移一位得到1010,(101&111)<<1。
第三步重复上述两步, 各位相加 010^1010=1000,进位值为100=(010&1010)<<1。
继续重复上述两步:1000^100 = 1100,进位值为0,跳出循环,1100为最终结果。
public class Solution { public int Add(int num1,int num2) { while (num2!=0) { int temp = num1^num2; num2 = (num1&num2)<<1; num1 = temp; } return num1; }}
49、把字符串转换成整数
此题主要是注意细节:
1、功能测试:输入有+-号情况,区分正负数和0
2、特殊输入:空字符串情况,输入非数字字符串情况,如a12
3、边界值:最大正整数和最小负整数溢出情况
public class Solution { public int StrToInt(String str) { if (str.equals("") || str.length() == 0) return 0; char[] a = str.toCharArray(); int i = 0; boolean fuhao = true; if (a[0] == '-'){ fuhao = false; i = 1; } int sum = 0; for (; i < a.length; i++) { if (a[i] == '+') continue; if (a[i] < 48 || a[i] > 57) return 0; sum = sum * 10 + a[i] - 48; if((fuhao && sum > 0X7fffffff) || (!fuhao && sum < 0X80000000)){ sum = 0; break; } } return fuhao ? sum : sum * -1; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
51、数组中重复的数
题目描述
在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是重复的数字2或者3。
思路1:排序,时间复杂度O(NlogN)
思路2:Hash表,时间和空间复杂度都是O(N)
import java.util.HashMap;import java.util.Iterator;import java.util.Map.Entry;public class Solution { boolean duplicate(int numbers[],int length,int [] duplication) { HashMap<Integer, Integer> countMap = new HashMap<Integer, Integer>(); if(length < 2||numbers==null){ return false; } int j = 1; for(int i = 0;i < length;i++){ if(countMap.get(numbers[i]) == null){ j = 1; countMap.put(numbers[i], j); }else{ j = countMap.get(numbers[i]); j++; countMap.put(numbers[i], j); } } Iterator iter = countMap.entrySet().iterator(); while(iter.hasNext()){ Entry<Integer, Integer> entry = (Entry<Integer, Integer>) iter.next(); Integer key = entry.getKey(); Integer val = countMap.get(key); if(val > 1){ duplication[0] = key; return true; } } return false; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
思路3:用Set集合,因为Set集合不允许有重复的,时间和空间复杂度都是O(N)
import java.util.Set;import java.util.HashSet;public class Solution { boolean duplicate(int numbers[], int length, int[] duplication) { if(length < 2||numbers==null){ return false; } Set<Integer> ss = new HashSet<Integer>(); for (int i = 0; i < numbers.length; i++) { if (ss.contains(numbers[i])) { duplication[0] = numbers[i]; return true; } else { ss.add(numbers[i]); } } return false; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
思路4better:时间复杂度O(N),所有操作都是在输入数组上进行,所以不需要分配额外空间,空间复杂度为O(1)
public class Solution { public boolean duplicate(int numbers[],int length,int [] duplication) { if(numbers==null||length<0)return false; for(int i = 0;i < length; i++){ if(numbers[i]<0||numbers[i]>length-1) return false; } for(int i = 0;i< length;i++){ while(numbers[i]!=i){ if(numbers[i]==numbers[numbers[i]]){ duplication[0] = numbers[i]; return true; } else{ swap(numbers,i,numbers[i]); } } } return false; } private void swap(int[]a, int i, int j){ int temp = a[i]; a[i] = a[j]; a[j] = temp; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
52、构建乘积数组
题目描述
给定一个数组A[0,1,…,n-1],请构建一个数组B[0,1,…,n-1],其中B中的元素B[i]=A[0] * A[1] * … * A[i-1]* A[i+1]* …*A[n-1]。不能使用除法。
思路:1.计算前i - 1个元素的乘积,及后N - i个元素的乘积分别保存在两个数组中
import java.util.ArrayList;public class Solution { public int[] multiply(int[] A) { int len = A.length; int forword[] = new int[len]; int backword[] = new int[len]; int B[] = new int[len]; forword[0] = 1; backword[0] = 1; for(int i = 1;i < len; i++){ forword[i] = A[i - 1]*forword[i-1]; backword[i] = A[len - i]*backword[i - 1]; } for(int i = 0; i < len; i++){ B[i] = forword[i] * backword[len - i -1]; } return B; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
53、正则表达式匹配
题目描述
请实现一个函数用来匹配包括’.’和’* ‘的正则表达式。模式中的字符’.’表示任意一个字符,而’* ’ 表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串”aaa”与模式”a.a”和”ab* ac* a”匹配,但是与”aa.a”和”ab*a”均不匹配
public class Solution { public boolean match(char[] str, char[] pattern) { if (str == null || pattern == null) { return false; } int strIndex = 0; int patternIndex = 0; return matchCore(str, strIndex, pattern, patternIndex);} public boolean matchCore(char[] str, int strIndex, char[] pattern, int patternIndex) { if (strIndex == str.length && patternIndex == pattern.length) { return true; } if (strIndex != str.length && patternIndex == pattern.length) { return false; } if (strIndex == str.length && patternIndex != pattern.length) { if (patternIndex + 1 < pattern.length && pattern[patternIndex + 1] == '*') { return matchCore(str, strIndex, pattern, patternIndex + 2); } return false; } if (patternIndex + 1 < pattern.length && pattern[patternIndex + 1] == '*') { if (pattern[patternIndex] == str[strIndex] || (pattern[patternIndex] == '.' && strIndex != str.length)) { return matchCore(str, strIndex, pattern, patternIndex + 2) || matchCore(str, strIndex + 1, pattern, patternIndex + 2) || matchCore(str, strIndex + 1, pattern, patternIndex); } else { return matchCore(str, strIndex, pattern, patternIndex + 2); } } if (pattern[patternIndex] == str[strIndex] || (pattern[patternIndex] == '.' && strIndex != str.length)) { return matchCore(str, strIndex + 1, pattern, patternIndex + 1); } return false; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
54、表示数值的字符串
题目描述
请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串”+100”,”5e2”,”-123”,”3.1416”和”-1E-16”都表示数值。 但是”12e”,”1a3.14”,”1.2.3”,”+-5”和”12e+4.3”都不是。
思路1:正则表达式
public class Solution { public boolean isNumeric(char[] str) { String string = String.valueOf(str); return string.matches("[\\+-]?[0-9]*(\\.[0-9]*)?([eE][\\+-]?[0-9]+)?"); }}
思路2:
public class Solution { boolean isNumeric(char[] s) { if (s.length == 0) return false; if ((s.length == 1) && (s[0] < '0' || s[0] > '9')) return false; if (s[0] == '+' || s[0] == '-') { if (s.length == 2 && (s[1] == '.')) return false; } else if ((s[0] < '0' || s[0] > '9') && s[0] != '.') return false; int i = 1; while ((i < s.length) && (s[i] >= '0' && s[i] <= '9')) i++; if (i < s.length && s[i] == '.') { i++; while ((i < s.length) && (s[i] >= '0' && s[i] <= '9')) i++; } if (i < s.length && (s[i] == 'e' || s[i] == 'E')) { i++; if ((i < s.length) && (s[i] == '+' || s[i] == '-')) { i++; if (i < s.length) while ((i < s.length) && (s[i] >= '0' && s[i] <= '9')) i++; else return false; } else if (i < s.length) { while ((i < s.length) && (s[i] >= '0' && s[i] <= '9')) i++; } else return false; } if (i < s.length) return false; return true; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
55、字符流中第一个不重复的字符
题目描述
请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符”go”时,第一个只出现一次的字符是”g”。当从该字符流中读出前六个字符“google”时,第一个只出现一次的字符是”l”。
import java.util.*;public class Solution { HashMap<Character, Integer> map=new HashMap(); ArrayList<Character> list=new ArrayList<Character>(); public void Insert(char ch) { if(map.containsKey(ch)){ map.put(ch,map.get(ch)+1); }else{ map.put(ch,1); } list.add(ch); } public char FirstAppearingOnce() { char c='#'; for(char key : list){ if(map.get(key)==1){ c=key; break; } } return c; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
56、链表中环的入口结点
题目描述
一个链表中包含环,请找出该链表的环的入口结点。
public class Solution { public ListNode EntryNodeOfLoop(ListNode pHead) { if (pHead == null || pHead.next == null) return null; ListNode n1 = pHead; ListNode n2 = pHead; ListNode n = null; while (n2 != null && n2.next != null) { n2 = n2.next.next; n1 = n1.next; if (n2 == n1) { n = n2; break; } } int num = 0; ListNode temp = n; do { temp = temp.next; num++; } while (temp != n); ListNode node1 = pHead; ListNode node2 = pHead; for (int i = 0; i < num; i++) { node1 = node1.next; } int num1 = 0; while (node1 != node2) { node1 = node1.next; node2 = node2.next; num1++; } return node1; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
57、删除链表中重复的结点
题目描述
在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5
思路:重点是第一个也可能是重复的点,因此新建一个preNode节点保存前一个节点
/** public class ListNode { int val; ListNode next = null; ListNode(int val) { this.val = val; }}*/public class Solution { public ListNode deleteDuplication(ListNode pHead) { if(pHead==null)return null; ListNode preNode = null; ListNode node = pHead; while(node!=null){ ListNode nextNode = node.next; boolean needDelete = false; if(nextNode!=null&&nextNode.val==node.val){ needDelete = true; } if(!needDelete){ preNode = node; node = node.next; }else{ int value = node.val; ListNode toBeDel = node; while(toBeDel!=null&&toBeDel.val == value){ nextNode = toBeDel.next; toBeDel = nextNode; if(preNode==null) pHead = nextNode; else preNode.next = nextNode; node = nextNode; } } } return pHead; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
58、二叉树的下一个结点
题目描述
给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
思路:画图分析,考虑三种情况
/**public class TreeLinkNode { int val; TreeLinkNode left = null; TreeLinkNode right = null; TreeLinkNode parent= null; TreeLinkNode(int val) { this.val = val; }}*/public class Solution { TreeLinkNode GetNext(TreeLinkNode node) { if(node==null) return null; if(node.right!=null){ node = node.right; while(node.left!=null) node = node.left; return node; } while(node.parent!=null){ if(node.parent.left==node) return node.parent; node = node.parent; } return null; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
59、对称的二叉树
题目描述
请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。
/**public class TreeNode { int val = 0; TreeNode left = null; TreeNode right = null; public TreeNode(int val) { this.val = val; }}*/public class Solution { boolean isSymmetrical(TreeNode pRoot) { return isSymmetrical(pRoot,pRoot); } boolean isSymmetrical(TreeNode pRoot1, TreeNode pRoot2) { if (pRoot1 == null && pRoot2 == null) return true; if (pRoot1 == null || pRoot2 == null) return false; if (pRoot1.val != pRoot2.val) return false; return isSymmetrical(pRoot1.left,pRoot2.right) && isSymmetrical(pRoot1.right, pRoot2.left); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
60、把二叉树打印成多行
题目描述
从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。
import java.util.*;/**public class TreeNode { int val = 0; TreeNode left = null; TreeNode right = null; public TreeNode(int val) { this.val = val; }}*/public class Solution { ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) { ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>(); if(pRoot == null){ return result; } Queue<TreeNode> layer = new LinkedList<TreeNode>(); ArrayList<Integer> layerList = new ArrayList<Integer>(); layer.add(pRoot); int start = 0, end = 1; while(!layer.isEmpty()){ TreeNode cur = layer.remove(); layerList.add(cur.val); start++; if(cur.left!=null){ layer.add(cur.left); } if(cur.right!=null){ layer.add(cur.right); } if(start == end){ end = layer.size(); start = 0; result.add(layerList); layerList = new ArrayList<Integer>(); } } return result; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
61、按之字形顺序打印二叉树
题目描述
请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。
思路1:按上一题的方式,还是用队列,用标记倒叙输出,但是有缺点
import java.util.*;/**public class TreeNode { int val = 0; TreeNode left = null; TreeNode right = null; public TreeNode(int val) { this.val = val; }}*/ public class Solution { /** * 缺点:将每层的数据存进ArrayList中,偶数层时进行reverse操作,但是在海量数据时,这样效率太低了。 */ public ArrayList<ArrayList<Integer>> Print(TreeNode pRoot) { ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>(); if(pRoot == null){ return result; } boolean leftToRight = true; Queue<TreeNode> layer = new LinkedList<TreeNode>(); ArrayList<Integer> layerList = new ArrayList<Integer>(); layer.add(pRoot); int start = 0, end = 1; while(!layer.isEmpty()){ TreeNode cur = layer.remove(); layerList.add(cur.val); start++; if(cur.left!=null){ layer.add(cur.left); } if(cur.right!=null){ layer.add(cur.right); } if(start == end){ end = layer.size(); start = 0; if(!leftToRight){ result.add(reverse(layerList)); }else{ result.add(layerList); } leftToRight = !leftToRight; layerList = new ArrayList<Integer>(); } } return result; } public ArrayList reverse(ArrayList<Integer> layerList) { int length = layerList.size(); ArrayList<Integer> reverseList = new ArrayList<Integer>(); for(int i = length-1; i >= 0;i--){ reverseList.add(layerList.get(i)); } return reverseList; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
思路1改进:用LinkedList,可以双向遍历,
Iterator iter = iter = queue.iterator();//从前往后遍历
Iterator iter = queue.descendingIterator();//从后往前遍历
import java.util.*;public class Solution { public ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) { ArrayList<ArrayList<Integer>> ret = new ArrayList<>(); if (pRoot == null) { return ret; } ArrayList<Integer> list = new ArrayList<>(); LinkedList<TreeNode> queue = new LinkedList<>(); queue.addLast(null); queue.addLast(pRoot); boolean leftToRight = true; while (queue.size() != 1) { TreeNode node = queue.removeFirst(); if (node == null) { Iterator<TreeNode> iter = null; if (leftToRight) { iter = queue.iterator(); } else { iter = queue.descendingIterator(); } leftToRight = !leftToRight; while (iter.hasNext()) { TreeNode temp = (TreeNode)iter.next(); list.add(temp.val); } ret.add(new ArrayList<Integer>(list)); list.clear(); queue.addLast(null); continue; } if (node.left != null) { queue.addLast(node.left); } if (node.right != null) { queue.addLast(node.right); } } return ret; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
思路2:用栈,先进后出,但是注意要用两个栈,因为如果用一个的话,本层的节点会压在最底下,此节点的子节点会放在最上边
import java.util.*;public class Solution { public ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) { ArrayList list=new ArrayList<ArrayList<Integer>>(); if(pRoot==null) return list; Stack s1=new Stack(); Stack s2=new Stack(); s1.push(pRoot); ArrayList arr=new ArrayList<Integer>(); while(true){ while(s1.size()!=0){ TreeNode node=(TreeNode)s1.pop(); arr.add(node.val); if(node.left!=null) s2.push(node.left); if(node.right!=null) s2.push(node.right); } list.add(arr); arr=new ArrayList<Integer>(); if(s1.size()==0&&s2.size()==0) break; while(s2.size()!=0){ TreeNode node1=(TreeNode)s2.pop(); arr.add(node1.val); if(node1.right!=null) s1.push(node1.right); if(node1.left!=null) s1.push(node1.left); } list.add(arr); arr=new ArrayList<Integer>(); if(s1.size()==0&&s2.size()==0) break; } return list; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
62、序列化二叉树
题目描述
请实现两个函数,分别用来序列化和反序列化二叉树
思路:通过前序遍历的顺序,但是修改了一下,子节点为null的用#表示
/**public class TreeNode { int val = 0; TreeNode left = null; TreeNode right = null; public TreeNode(int val) { this.val = val; } }*/public class Solution { public int index = -1; public String Serialize(TreeNode root) { StringBuffer sb = new StringBuffer(); if(root == null){ sb.append("#,"); return sb.toString(); } sb.append(root.val + ","); sb.append(Serialize(root.left)); sb.append(Serialize(root.right)); return sb.toString(); } public TreeNode Deserialize(String str) { index++; int len = str.length(); if(index >= len){ return null; } String[] strr = str.split(","); TreeNode node = null; if(!strr[index].equals("#")){ node = new TreeNode(Integer.valueOf(strr[index])); node.left = Deserialize(str); node.right = Deserialize(str); } return node; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
63、二叉搜索树的第K个节点
题目描述
给定一颗二叉搜索树,请找出其中的第k大的结点。例如, 5 / \ 3 7 /\ /\ 2 4 6 8 中,按结点数值大小顺序第三个结点的值为4。
思路:中序遍历就是二叉搜索树的排序,不用递归的程序
/**public class TreeNode { int val = 0; TreeNode left = null; TreeNode right = null; public TreeNode(int val) { this.val = val; }}*/import java.util.*;public class Solution { TreeNode KthNode(TreeNode pRoot, int k) { Stack<TreeNode> stack = new Stack<TreeNode>(); if(pRoot==null||k==0) return null; int t=0; while(pRoot!=null ||stack.size()>0){ while(pRoot!=null){ stack.push(pRoot); pRoot = pRoot.left; } if(stack.size()>0){ pRoot= stack.pop(); t++; if(t==k) return pRoot; pRoot= pRoot.right; } } return null; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
64、数据流中的中位数
题目描述
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。
import java.util.*;public class Solution{ private Heap maxHeap = new Heap(Heap.isMaxHeap); private Heap minHeap = new Heap(Heap.isMinHeap); /** * 插入有两种思路: * 1:直接插入大堆中,之后若两堆尺寸之差大于1(也就是2),则从大堆中弹出堆顶元素并插入到小堆中 * 若两队之差不大于1,则直接插入大堆中即可。 * 2:奇数个数插入到大堆中,偶数个数插入到小堆中, * 但是 可能会出现当前待插入的数比小堆堆顶元素大,此时需要将元素先插入到小堆,然后将小堆堆顶元素弹出并插入到大堆中 * 对于偶数时插入小堆的情况,一样的道理。why? * 因为要保证最大堆的元素要比最小堆的元素都要小。 * @param num */ public void Insert(Integer num) { if(((maxHeap.size() + minHeap.size()) & 1) == 0){ if(minHeap.size() != 0 && num > minHeap.peek()){ minHeap.add(num); maxHeap.add(minHeap.pop()); }else{ maxHeap.add(num); } }else{ if(maxHeap.size() != 0 && num < maxHeap.peek()){ maxHeap.add(num); minHeap.add(maxHeap.pop()); }else{ minHeap.add(num); } } } public Double GetMedian() { double res = 0.0; if(((maxHeap.size() + minHeap.size()) & 1) == 0){ res = (maxHeap.peek() + minHeap.peek()) / 2.0; }else{ res = maxHeap.peek(); } return res; } class Heap { public List<Integer> list = null; public static final boolean isMaxHeap = true; public static final boolean isMinHeap = false; private boolean flag = true; public Heap(){ this.list = new ArrayList<Integer>(); } public Heap(boolean flag){ this.list = new ArrayList<Integer>(); this.flag = flag; } public int size(){ return this.list.size(); } public int peek(){ if(list.size() == 0) return 0; return list.get(0); } public void add(int val){ this.list.add(val); int i = list.size() - 1, index, parent, cur; while(i > 0){ index = (i - 1) / 2; parent = list.get(index); cur = list.get(i); if(flag == true && parent < cur){ swap(index, i); }else if(flag == false && parent > cur){ swap(index, i); } i = index; } } /** * 将堆顶元素取出,并重新调整堆。 * 1>取出堆顶元素 * 2>将最后一个元素放到堆顶 * 3>向下调整堆 */ public int pop(){ if(list.size() == 0) return -1; int res = list.get(0); list.set(0,list.get(list.size() - 1)); list.remove(list.size()-1); int len = list.size() - 1 , i = 0; int left , right; while(i < len){ left = (i << 1) + 1; right= (i << 1) + 2; int maxIndex = i; if(flag == true){ if(left < len && list.get(left) > list.get(maxIndex)) maxIndex = left; if(right< len && list.get(right)> list.get(maxIndex)) maxIndex = right; }else{ if(left < len && list.get(left) < list.get(maxIndex)) maxIndex = left; if(right< len && list.get(right)< list.get(maxIndex)) maxIndex = right; } if(maxIndex != i){ swap(maxIndex,i); i = maxIndex; }else break; } return res; } public void swap(int i, int j){ int temp = list.get(i); list.set(i, list.get(j)); list.set(j,temp); } }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
思路2:
import java.util.ArrayList;import java.util.Comparator;/** * 数据流中的中位数 * * @author 过路的守望 * */public class Solution { private Heap maxHeap = new Heap(new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return o1 - o2; } }); private Heap minHeap = new Heap(new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return o2 - o1; } }); public void Insert(Integer num) { if (maxHeap.getSize() >= minHeap.getSize()) { if (minHeap.getSize() == 0) { minHeap.add(num); } else if (num < maxHeap.peek()) { minHeap.add(maxHeap.pop()); maxHeap.add(num); } else { minHeap.add(num); } } else { if (maxHeap.getSize() == 0) { maxHeap.add(num); } else if (num > minHeap.peek()) { maxHeap.add(minHeap.pop()); minHeap.add(num); } else { maxHeap.add(num); } } } public Double GetMedian() { int size = maxHeap.getSize() + minHeap.getSize(); if ((size & 1) == 1) { return (double) minHeap.peek(); } return (maxHeap.peek() + minHeap.peek()) / 2.0; }}/** * 数据结构-堆 * * @author 过路的守望 * */class Heap { private Comparator<Integer> comparator; private ArrayList<Integer> list; public Heap() { list = new ArrayList<Integer>(); } public Heap(Comparator<Integer> comparator) { this(); this.comparator = comparator; } public int pop() { int data = list.get(0); list.set(0, list.remove(list.size() - 1)); percolateDown(); return data; } public int peek() { return list.get(0); } public void add(int element) { list.add(element); percolateUp(); return; } public int getSize() { return list.size(); } private void percolateDown() { int size = list.size(); int i = 0; int temp = list.get(0); int leftChild = getLeftChild(i); while (leftChild < size) { if (leftChild < size - 1 && comparator.compare(list.get(leftChild), list.get(leftChild + 1)) < 0) { leftChild++; } if (comparator.compare(temp, list.get(leftChild)) < 0) { list.set(i, list.get(leftChild)); i = leftChild; leftChild = getLeftChild(i); continue; } else { break; } } list.set(i, temp); } private void percolateUp() { int i = list.size() - 1; int temp = list.get(i); int parent = getParent(i); while (parent >= 0) { if (comparator.compare(temp, list.get(parent)) > 0) { list.set(i, list.get(parent)); i = parent; parent = getParent(parent); continue; } else { break; } } list.set(i, temp); } private int getLeftChild(int i) { return 2 * i + 1; } private int getParent(int i) { return (int) Math.floor((i - 1) / 2.0); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
65、滑动窗口的最大值
题目描述
给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。
import java.util.*;/** * 题目:滑动窗口的最大值 * 思路:滑动窗口应当是队列,但为了得到滑动窗口的最大值,队列序可以从两端删除元素,因此使用双端队列。 * 原则: * 对新来的元素k,将其与双端队列中的元素相比较 * 1)前面比k小的,直接移出队列(因为不再可能成为后面滑动窗口的最大值了!), * 2)前面比k大的X,比较两者下标,判断X是否已不在窗口之内,不在了,直接移出队列 * 队列的第一个元素是滑动窗口中的最大值 */public class Solution { public ArrayList<Integer> maxInWindows(int [] num, int size) { ArrayList<Integer> ret = new ArrayList<>(); if (num == null) { return ret; } if (num.length < size || size < 1) { return ret; } LinkedList<Integer> indexDeque = new LinkedList<>(); for (int i = 0; i < size - 1; i++) { while (!indexDeque.isEmpty() && num[i] > num[indexDeque.getLast()]) { indexDeque.removeLast(); } indexDeque.addLast(i); } for (int i = size - 1; i < num.length; i++) { while (!indexDeque.isEmpty() && num[i] > num[indexDeque.getLast()]) { indexDeque.removeLast(); } indexDeque.addLast(i); if (i - indexDeque.getFirst() + 1 > size) { indexDeque.removeFirst(); } ret.add(num[indexDeque.getFirst()]); } return ret; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50