leetcode java版本_《剑指Offer》Java版本 LeetCode

2 单例模式

双重检验懒汉式单例模式java

// 懒汉式(线程安全,同步方法)

class Singleton {

//volatile禁止重排序,保证可见性

private static volatile Singleton instance;

private Singleton() {}//私有化构造方法

//提供一个静态的公有方法,加入双重检查代码,解决线程安全问题, 同时解决懒加载问题

//同时保证了效率, 推荐使用

public static synchronized Singleton getInstance() {

if(instance == null) {

synchronized (Singleton.class) {

if(instance == null) {

instance = new Singleton();

}

}

}

return instance;

}

}

3 数组中重复的数字(Hash)

LeetCode地址

题目描述:

在一个长度为 n 的数组 nums 里的全部数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每一个数字重复了几回。请找出数组中任意一个重复的数字。

思路:

(1)HashSet找重复数字

(2)数组交换,利用 0~n-1这个条件,相似位图的思想。边排序边判断。

代码:node

class Solution {

public int findRepeatNumber(int[] nums) {

for(int i=0;i

while(nums[i]!=i){

//不等的话,进行交换

if(nums[i]==nums[nums[i]]){

//若是已经存在数字了,说明重复

return nums[i];

}

int tmp=nums[i];

nums[i]=nums[tmp];

nums[tmp]=tmp;

}

}

return -1;

}

}

考虑另一种状况,若是不容许交换数组中元素,如何解决?

方法一:git

import java.util.*;

class Solution {

public int findRepeatNumber(int[] nums) {

HashSet set=new HashSet<>();

for(int i=0;i

if(set.contains(nums[i]))

return nums[i];

else set.add(nums[i]);

}

return -1;

}

}

4 二维数组中的查找

题目描述:

在一个 n * m 的二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

思路: 从右上角/左下角开始查找数组面试

class Solution {

public boolean findNumberIn2DArray(int[][] matrix, int target) {

if(matrix.length<=0)return false;

int i=0;

int j=matrix[0].length-1;

while(j>=0&&i

if(matrix[i][j]==target){

return true;

}else if(matrix[i][j]

i++;

}else{

j--;

}

}

return false;

}

}

5 替换空格

LeetCode地址

题目描述:

请实现一个函数,把字符串 s 中的每一个空格替换成"%20"。

思路:注意不要覆盖(Java的String不须要考虑这个)正则表达式

class Solution {

public String replaceSpace(String s) {

char arr[]=s.toCharArray();

StringBuilder ret=new StringBuilder("");

for(int i=0;i

if(arr[i]==' '){

ret.append("%20");

}else{

ret.append(arr[i]);

}

}

return ret.toString();

}

}

6 从尾到头打印链表(栈)

LeetCode地址

题目描述:

输入一个链表的头节点,从尾到头反过来返回每一个节点的值(用数组返回)。

思路:

(1)翻转链表以后再遍历

(2)利用栈,推荐

(3)递归的方式,链表很长可能会栈溢出,不推荐

栈的方式:编程

/**

* Definition for singly-linked list.

* public class ListNode {

* int val;

* ListNode next;

* ListNode(int x) { val = x; }

* }

*/

import java.util.Stack;

class Solution {

public int[] reversePrint(ListNode head) {

Stack stack=new Stack<>();

while(head!=null){

stack.add(head);

head=head.next;

}

int ret[]=new int[stack.size()];

int len=0;

while(!stack.isEmpty()){

ret[len++]=stack.pop().val;

}

return ret;

}

}

7 重建二叉树(递归)

LeetCode地址

题目描述:

输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。

代码:数组

/**

* Definition for a binary tree node

* public class TreeNode {

* int val;

* TreeNode left;

* TreeNode right;

* TreeNode(int x) { val = x; }

* }

*/

class Solution {

public TreeNode buildTree(int[] preorder, int[] inorder) {

if(preorder.length<1||inorder.length<1) return null;

TreeNode node=new TreeNode(preorder[0]);

TreeNode leftN=null;

TreeNode rightN=null;

for(int i=0;i

if(inorder[i]==node.val){

leftN=buildTree(Arrays.copyOfRange(preorder,1,i+1),Arrays.copyOfRange(inorder,0,i));

rightN=buildTree(Arrays.copyOfRange(preorder,i+1,preorder.length),Arrays.copyOfRange(inorder,i+1,inorder.length));

break;

}

}

node.left=leftN;

node.right=rightN;

return node;

}

}

8 二叉树的下一个节点

牛客网地址

题目描述:

给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点而且返回。注意,树中的结点不只包含左右子结点,同时包含指向父结点的指针。

思路:判断是否有右子树安全

/*

public class TreeLinkNode {

int val;

TreeLinkNode left = null;

TreeLinkNode right = null;

TreeLinkNode next = null;

TreeLinkNode(int val) {

this.val = val;

}

}

*/

public class Solution {

public TreeLinkNode GetNext(TreeLinkNode pNode)

{

if(pNode==null) return null;

if(pNode.right!=null){//结点有右子树

//找右子树最左边的结点

pNode=pNode.right;

while(pNode.left!=null){

pNode=pNode.left;

}

return pNode;

}else{//结点没有右子树

//向上找到结点是父结点的左结点的结点

while(pNode.next!=null&&pNode==pNode.next.right){

pNode=pNode.next;

}

return pNode.next;

}

}

}

9 用两个栈实现队列(栈)

LeetCode地址

题目描述:

用两个栈实现一个队列。队列的声明以下,请实现它的两个函数 appendTail 和 deleteHead ,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead 操做返回 -1 )

思路:

方法一,stack1始终存放压入队列的正序,stack2来倒换数据

方法二,对方法一改进,判断stack2若是为空再把stack1导入进来,stack2不为空直接返回栈顶元素

方法一:数据结构

import java.util.Stack;

class CQueue {

Stack stack1;

Stack stack2;

public CQueue() {

stack1=new Stack<>();

stack2=new Stack<>();

}

public void appendTail(int value) {

stack1.add(value);

}

public int deleteHead() {

//stack1放到stack2中

while(!stack1.isEmpty()){

stack2.add(stack1.pop());

}

if(stack2.isEmpty()){

return -1;

}else{//stack2的数据倒回stack1

int ret=stack2.pop();

while(!stack2.isEmpty()){

stack1.add(stack2.pop());

}

return ret;

}

}

}

方法二:

import java.util.Stack;

class CQueue {

Stack stack1;

Stack stack2;

public CQueue() {

stack1=new Stack<>();

stack2=new Stack<>();

}

public void appendTail(int value) {

stack1.add(value);

}

public int deleteHead() {

if(stack2.isEmpty()){

if(stack1.isEmpty()){

return -1;

}else{

while(!stack1.isEmpty()){

stack2.add(stack1.pop());

}

return stack2.pop();

}

}else{

return stack2.pop();

}

}

}

10 I 斐波那契数列(循环)

LeetCode地址

题目描述:

斐波那契数列由 0 和 1 开始,以后的斐波那契数就是由以前的两数相加而得出。

class Solution {

public int fib(int n) {

if(n<=1) return n;

int opt1=0;

int opt2=1;

int ret=0;

for(int i=0;i

ret=(opt1+opt2)%1000000007;

opt1=opt2;

opt2=ret;

}

return ret;

}

}

10 II青蛙跳台阶问题(循环)

LeetCode地址

题目描述:

一只青蛙一次能够跳上1级台阶,也能够跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。

class Solution {

public int numWays(int n) {

if(n<=1) return 1;

int opt1=1;

int opt2=1;

int ret=0;

for(int i=0;i

ret=(opt1+opt2)%1000000007;

opt1=opt2;

opt2=ret;

}

return ret;

}

}

11 旋转数组的最小数字(二分)

LeetCode地址

题目描述:

把一个数组最开始的若干个元素搬到数组的末尾,咱们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一个旋转,该数组的最小值为1。

方法一:复杂度为O(n)

class Solution {

public int minArray(int[] numbers) {

for(int i=1;i

if(numbers[i-1]>numbers[i])

return numbers[i];

}

return numbers[0];

}

}

方法二:复杂度为O(logn) 二分法

class Solution {

public int minArray(int[] numbers) {

int left=0;

int right=numbers.length-1;

int mid;

while(left

mid=(left+right)>>1;

//没法判断有序

if(numbers[mid]==numbers[right]){

right--;

continue;

}//没法判断有序

if(numbers[mid]==numbers[left]){

left++;

continue;

}

if(numbers[mid]

right=mid;

}else if(numbers[left]

left=mid;

}

}

return Math.min(numbers[left],numbers[right]);

}

}

12 矩阵中的路径(回溯)

LeetCode地址

题目描述:

请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串全部字符的路径。

class Solution {

public boolean exist(char[][] board, String word) {

for(int i=0;i

for(int j=0;j

if(backTrace(board,word,0,i,j)){

return true;

}

}

}

return false;

}

public boolean backTrace(char[][] board,String target,int len,int row,int col){

if(row<0||row>=board.length||col<0||col>=board[0].length||

board[row][col]!=target.charAt(len)) return false;

if(len==target.length()-1){

return true;

}else{

char tmp=board[row][col];

board[row][col]='*';

len++;

if(backTrace(board,target,len,row-1,col)||

backTrace(board,target,len,row+1,col)||

backTrace(board,target,len,row,col-1)||

backTrace(board,target,len,row,col+1)){

return true;

}else{

board[row][col]=tmp;

return false;

}

}

}

}

13 机器人的运动范围(回溯)

LeetCode地址

题目描述:

地上有一个m行n列的方格,从坐标 [0,0] 到坐标 [m-1,n-1] 。一个机器人从坐标 [0, 0] 的格子开始移动,它每次能够向左、右、上、下移动一格(不能移动到方格外),也不能进入行坐标和列坐标的数位之和大于k的格子。例如,当k为18时,机器人可以进入方格 [35, 37] ,由于3+5+3+7=18。但它不能进入方格 [35, 38],由于3+5+3+8=19。请问该机器人可以到达多少个格子?

class Solution {

int count=0;

public int movingCount(int m, int n, int k) {

boolean []flag=new boolean[m*n];

for(int i=0;i

flag[i]=false;

}

backTrace(0,0,m,n,flag,k);

return count;

}

public void backTrace(int row,int col,int m,int n,boolean[] flag,int k){

if(row<0||col<0||row>=m||col>=n) return;

if(!flag[row*n+col]&&isValid(row,col,k)){

count++;

flag[row*n+col]=true;//使其不会重复计数

backTrace(row-1,col,m,n,flag,k);

backTrace(row+1,col,m,n,flag,k);

backTrace(row,col-1,m,n,flag,k);

backTrace(row,col+1,m,n,flag,k);

}

}//判断位数之和是否大于k

public boolean isValid(int row,int col,int k){

int tmp1=0;

int tmp2=0;

while(row!=0){

tmp1+=row%10;

row=row/10;

}

while(col!=0){

tmp2+=col%10;

col=col/10;

}

if(tmp1+tmp2<=k){

return true;

}else{

return false;

}

}

}

14 I 剪绳子 (动归)

LeetCode地址

题目描述:

给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1而且m>1),每段绳子的长度记为 k[0],k[1]…k[m] 。请问 k[0]k[1]…*k[m] 可能的最大乘积是多少?例如,当绳子的长度是8时,咱们把它剪成长度分别为二、三、3的三段,此时获得的最大乘积是18。

方法一:动归

class Solution {

public int cuttingRope(int n) {

int dp[]=new int[n+1];

if(n<=2) return 1;

if(n==3) return 2;

//dp[i]表示长度为i的最大乘积

dp[0]=0;

dp[1]=1;

dp[2]=2;

dp[3]=3;

for(int i=4;i

int tmp=Integer.MIN_VALUE;

for(int j=1;j<=i/2;j++){

if(dp[j]*dp[i-j]>tmp){

tmp=dp[j]*dp[i-j];

}

}

dp[i]=tmp;

}

return dp[n];

}

}

方法二:贪婪

public int cuttingRope(int n) {

int dp[]=new int[n+1];

if(n<=2) return 1;

if(n==3) return 2;

int num3=n/3;

if(n-num3*3==1){//剩下为1的时候,最好4=2*2

num3--;

}

int num2=(n-num3*3)/2;

int ret=(int)Math.pow(3,num3)*(int)Math.pow(2,num2);

return ret;

}

14 II 剪绳子(贪婪)

LeetCode地址

题目描述:大整数求余问题

答案须要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。

方法一:循环求幂

class Solution {

public int cuttingRope(int n) {

int dp[]=new int[n+1];

if(n<=2) return 1;

if(n==3) return 2;

int num3=n/3;

if(n-num3*3==1){

num3--;

}

int num2=(n-num3*3)/2;

//!!注意这里

long tmp=cpow(3,num3,(int)Math.pow(2, num2));

int ret=(int)tmp%1000000007;

return ret;

}

//求幂函数

public long cpow(int pow,int n,int start){

long ret=start;

while(n>0){

ret=(ret*pow)%1000000007;

n--;

}

return ret;

}

}

方法二:快速幂

11的二进制为1011,

4e681e8b68ad6f25adc751840ede1376.png

那么 a^11为:

8d29aba80bb8c3950eaff1d668eb0b9b.png

修改求幂函数为:

//快速幂

public long cpow1(long pow,int n,int start){

long ret=start;

while(n>0){

if((n&1)==1){//取最后一位是0仍是1

ret=(ret*pow)%1000000007;

}

n=n>>1;

pow=pow*pow%1000000007;//底数为原来的平方,a 的2次方,a的4次方 ,a的8次方

}

return ret;

}

15 二进制中1的个数(位运算)

LeetCode地址

题目描述:

请实现一个函数,输入一个整数,输出该数二进制表示中 1 的个数。例如,把 9 表示成二进制是 1001,有 2 位是 1。所以,若是输入 9,则该函数输出 2。

思路:

普通解法,若是输入是负数会出现死循环的问题(由于负数右移时会补1,正数右移时补0)。

方法一:用右移mask代替左移n。每次须要循环32次。

public class Solution {

// you need to treat n as an unsigned value

public int hammingWeight(int n) {

int ret=0;

int tmp=1;

while(tmp!=0){

if((n&tmp)==tmp){

ret++;

}

tmp=tmp<<1;

}

return ret;

}

}

方法二:考虑(n-1)&n,

n-1表示把最后一位的1变为0,0以后的数为1

(n-1)&n表示把n的最后一位的1变为0。

例子:n=1011的状况,

195cab3bb3dc043f7b4a7feb752854b7.png

public class Solution {

// you need to treat n as an unsigned value

public int hammingWeight(int n) {

int ret=0;

while(n!=0){

n=n&(n-1);

ret++;

}

return ret;

}

}

相关题目:

(1)判断整数是不是2的整数次方: (n-1)&n==0

(2)改变m二进制多少位获得n:异或后求1的位数

16 数值的整数次方(快速幂)

LeetCode地址

题目描述:实现函数double Power(double base, int exponent),求base的exponent次方。不得使用库函数,同时不须要考虑大数问题。

注意:int32的取值范围是[-2147483648,2147483647],输入为2.0,-2147483648的状况会越界,解决办法用long操做inf

class Solution {

public double myPow(double x, int n) {

//快速幂

if(x==0.0) return 0.0;

if(n==1) return x;

double ret=1;

long tmp=n;//注意这里!!用long类型存储n

long n1=Math.abs(tmp);

while(n1!=0){

if((n1&1)==1)

ret=ret*x;

n1=n1>>1;

x=x*x;

}

if(n>=0) return ret;

else{

return 1.0/ret;

}

}

}

17 打印从1到最大的n位数

LeetCode地址

题目描述:

输入数字 n,按顺序打印出从 1 到最大的 n 位十进制数。好比输入 3,则打印出 一、二、3 一直到最大的 3 位数 999。

class Solution {

public int[] printNumbers(int n) {

int len=1;

while(n>0){

len=len*10;

n--;

}

len--;

int []ret=new int[len];

len=1;

for(int i=0;i

ret[i]=len;

len++;

}

return ret;

}

}

相关题目:考虑大数的状况,解决办法:用字符串存大数

18 删除链表的节点(链表)

LeetCode地址

题目描述:

给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。

返回删除后的链表的头节点。

方法一:存储前一个节点,pre–>thisNode.next

class Solution {

public ListNode deleteNode(ListNode head, int val) {

ListNode top=new ListNode(0);

top.next=head;

ListNode node=head;

ListNode tmp=top;

while(node!=null){

if(node.val==val){

tmp.next=node.next;

break;

}

tmp=node;

node=node.next;

}

return top.next;

}

}

方法二:复制this节点next节点的val给this节点,this节点的next指向next节点的next

631402372c4aa6a6149b79eb39b82490.png

19 正则表达式匹配(递归)

LeetCode 地址 面试题19. 正则表达式匹配

题目描述:

请实现一个函数用来匹配包含’. ‘和’‘的正则表达式。模式中的字符’.‘表示任意一个字符,而’'表示它前面的字符能够出现任意次(含0次)。在本题中,匹配是指字符串的全部字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"abaca"匹配,但与"aa.a"和"ab*a"均不匹配。

class Solution {

public boolean isMatch(String s, String p) {

if(s==null||p==null) return false;

return matchCore(s,p,0,0);

}

public boolean matchCore(String s,String p,int points,int pointp){

if(s.length()==points&&p.length()==pointp) return true;

if(s.length()>points&&p.length()==pointp) return false;

//下一个为*的状况

if(pointp+1

//判断当前是不是. 或者相等

if((points

(points

return matchCore(s,p,points,pointp+2)|| //忽略b*

matchCore(s,p,points+1,pointp+2)|| //选择一个

matchCore(s,p,points+1,pointp); //选择多个

}else{//忽略b*

return matchCore(s,p,points,pointp+2);

}

}

//正常继续递归 s和p相等或者p是.

if(points

return matchCore(s,p,points+1,pointp+1);

}

return false;

}

}

20 表示数值的字符串(考察状况考虑是否完整)

class Solution {

public boolean isNumber(String s) {

//A.B e/E A

if(s==null) return false;

s=s.trim();

boolean ret=isA(s)||isB(s);

if(ret) return true;

ret=isDouble(s);

if(ret) return true;

int index=s.indexOf("e");

if(index+1

//e前面是A A.B .B B

ret=isDouble(s.substring(0,index))||isA(s.substring(0,index))||isB(s.substring(0,index));

//e后面是B

ret= ret&&(isB(s.substring(index+1,s.length()))||isA(s.substring(index+1,s.length())));

}

if(ret) return true;

index=s.indexOf("E");

if(index+1

//e前面是A A.B .B B

ret=isDouble(s.substring(0,index))||isA(s.substring(0,index))||isB(s.substring(0,index));

//e后面是B

ret= ret&&(isB(s.substring(index+1,s.length()))||isA(s.substring(index+1,s.length())));

}

if(ret) return true;

return false;

}

//判断是不是 A.B|.B |B. | A.

public boolean isDouble(String s) {

if(s.length()>0&&(s.charAt(0)=='+'||s.charAt(0)=='-')){

s=s.substring(1,s.length());

}

int index=s.indexOf(".");

boolean ret=false;

if(index!=-1){//是不是A.B .B B.

boolean dotPre=isA(s.substring(0,index))||isB(s.substring(0,index));

boolean dotAfter=false;

if(index+1

dotAfter=isB(s.substring(index+1,s.length()));

ret=(dotPre&&dotAfter)||(index==0&&dotAfter);

}else{

ret=index==s.length()-1&&dotPre;

}

}

return ret;

}

//判断是不是有符号整数

public boolean isA(String s){

if(s.length()>0&&(s.charAt(0)=='+'||s.charAt(0)=='-')){

if(isB(s.substring(1,s.length())))

return true;

}

return false;

}

//判断是不是无符号整数

public boolean isB(String s){

if(s.length()<1){

return false;

}

for(int i=0;i

if(!Character.isDigit(s.charAt(i))){

return false;

}

}

return true;

}

}

21 调整数组顺序使奇数位于偶数前面(双指针 模拟快排)

class Solution {

public int[] exchange(int[] nums) {

if(nums==null) return null;

int low=0;

int high=nums.length-1;

while(low

while(low

low++;

while(low

high--;

int tmp=nums[low];

nums[low]=nums[high];

nums[high]=tmp;

}

return nums;

}

}

22 链表中倒数第k个节点(双指针)

面试题22. 链表中倒数第k个节点

注意代码的鲁棒性!

考虑输入为k=0,k>链表长度,head==null的状况

class Solution {

public ListNode getKthFromEnd(ListNode head, int k) {

if(head==null||k<=0) return null;//here!!!!

ListNode low=head;

ListNode high=head;

while(high!=null&&k-1>0){

high=high.next;

k--;

}

while(high!=null&&high.next!=null){//here

high=high.next;

low=low.next;

}

return low;

}

}

23 链表中环的入口节点(双指针)

142. 环形链表 II LeetCode

题目描述:

给定一个链表,返回链表开始入环的第一个节点。 若是链表无环,则返回 null。

为了表示给定链表中的环,咱们使用整数 pos 来表示链表尾链接到链表中的位置(索引从 0 开始)。 若是 pos 是 -1,则在该链表中没有环。

说明:不容许修改给定的链表。

方法一:Hashset

Set set=new HashSet<>();

ListNode temp=new ListNode(0);

int count=0;

while(head!=null){

count++;

set.add(head);

if (set.size()!=count) {

temp=head;

break;

}

head=head.next;

}

if (head==null) {

return null;

}

return temp;

方法二:双指针

public class Solution {

//判断是否有环,有环返回环中的位置

public ListNode hasCycle(ListNode head) {

ListNode node=head;//慢指针

while(head!=null&&head.next!=null){

head=head.next.next;

node=node.next;

if(head==node) return head;

}

return null;

}

public ListNode detectCycle(ListNode head) {

ListNode node=hasCycle(head);

if(node==null) return null;

//找出环中节点数量

int len=1;

ListNode tmp=node;

while(node.next!=tmp){

node=node.next;

len++;

}

//双指针找到节点

node=head;

tmp=head;

while(len>0){

node=node.next;

len--;

}

while(node!=tmp){

node=node.next;

tmp=tmp.next;

}

return node;

}

}

24 反转链表(考察状况考虑是否完整)

面试题24. 反转链表 LeetCode

题目描述:

定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。

class Solution {

public ListNode reverseList(ListNode head) {

if(head==null) return null;//输入空节点

if(head.next==null) return head; //输入只有一个节点

ListNode pre=head;

ListNode thisNode=head.next;

ListNode nextNode=thisNode.next;

pre.next=null;//注意这里 若是不设置会有环产生

while(thisNode!=null){

nextNode=thisNode.next;

thisNode.next=pre;

pre=thisNode;

thisNode=nextNode;

}

return pre;

}

}

25 合并两个排序的链表(相似归并)

面试题25. 合并两个排序的链表 LeetCode地址

题目描述:

输入两个递增排序的链表,合并这两个链表并使新链表中的节点仍然是递增排序的。

class Solution {

public ListNode mergeTwoLists(ListNode l1, ListNode l2) {

ListNode head=new ListNode(-1);

ListNode node=head;

while(l1!=null&&l2!=null){

if(l1.val

node.next=l1;

l1=l1.next;

}else{

node.next=l2;

l2=l2.next;

}

node=node.next;

}

if(l1!=null){

node.next=l1;

}

if(l2!=null){

node.next=l2;

}

return head.next;

}

}

26 树的子结构 (递归)

面试题26. 树的子结构

题目描述:输入两棵二叉树A和B,判断B是否是A的子结构。(约定空树不是任意一个树的子结构),B是A的子结构, 即 A中有出现和B相同的结构和节点值。

class Solution {

public boolean isSubStructure(TreeNode A, TreeNode B) {

if(A==null||B==null) return false;//注意边界

//A.val==B.val就判断是不是子树,不等就在左子树和右子树中寻找

return isSubTree(A,B)|| isSubStructure(A.left,B)||isSubStructure(A.right,B);

}

public boolean isSubTree(TreeNode A,TreeNode B){

if(B!=null&&A==null) return false;

if(B==null) return true;

if(A.val==B.val){

return isSubTree(A.left,B.left)&&isSubTree(A.right,B.right);

}else{

return false;

}

}

}

27 二叉树的镜像(递归)

面试题27. 二叉树的镜像 LeetCode地址

题目描述:请完成一个函数,输入一个二叉树,该函数输出它的镜像。

class Solution {

public TreeNode mirrorTree(TreeNode root) {

if(root==null) return null;

TreeNode left=mirrorTree(root.left);

TreeNode right=mirrorTree(root.right);

root.left=right;

root.right=left;

return root;

}

}

28 对称的二叉树(递归)

题目描述:

请实现一个函数,用来判断一棵二叉树是否是对称的。若是一棵二叉树和它的镜像同样,那么它是对称的。

/**

* Definition for a binary tree node.

* public class TreeNode {

* int val;

* TreeNode left;

* TreeNode right;

* TreeNode(int x) { val = x; }

* }

*/

class Solution {

public boolean isSymmetric(TreeNode root) {

if(root==null) return true;

else return core(root.left, root.right);

}

public boolean core(TreeNode left,TreeNode right){

if(left==null&&right==null) return true;

if(left==null||right==null||left.val!=right.val) return false;

return core(left.left,right.right)&&core(left.right,right.left);

}

}

29 顺时针打印矩阵

LeetCode地址

题目描述:输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每个数字。

class Solution {

public int[] spiralOrder(int[][] matrix) {

if(matrix==null) return null;

int [] ret=new int[matrix.length];

if(matrix.length<1) return ret;

int rowCount=matrix.length;

int colCount=matrix[0].length;

ret=new int[rowCount*colCount];

int index=0;

int rowStart=0;

int colStart=0;

rowCount--;

colCount--;

while(index<=matrix.length*matrix[0].length-1){

index=printCircle(matrix,ret,index,rowStart,colStart,rowCount,colCount);

rowStart++;

colStart++;

rowCount--;

colCount--;

}

return ret;

}

//打印一圈

public int printCircle(int[][] matrix,int[]ret,int index,int rowStart,int colStart,int rowCount,int colCount){

//若是是一行

if(rowStart==rowCount){

for(int i=colStart;i<=colCount;i++){

ret[index++]=matrix[rowStart][i];

}

return index;

}//若是是一列

if(colStart==colCount){

for(int i=rowStart;i<=rowCount;i++){

ret[index++]=matrix[i][colCount];

}

return index;

}

//从左到右打印一行

for(int i=colStart;i<=colCount;i++){

ret[index++]=matrix[rowStart][i];

}

//从上到下打印一列

for(int i=rowStart+1;i<=rowCount;i++){

ret[index++]=matrix[i][colCount];

}

//从右向左打印一行

for(int i=colCount-1;i>=colStart;i--){

ret[index++]=matrix[rowCount][i];

}

//从下到上打印一列

for(int i=rowCount-1;i>rowStart;i--){

ret[index++]=matrix[i][colStart];

}

return index;

}

}

30 包含min函数的栈(辅助栈)

题目描述:

定义栈的数据结构,请在该类型中实现一个可以获得栈的最小元素的 min 函数在该栈中,调用 min、push 及 pop 的时间复杂度都是 O(1)。

import java.util.Stack;

class MinStack {

/** initialize your data structure here. */

Stack stack;

Stack minstack;

public MinStack() {

stack=new Stack<>();

minstack=new Stack<>();

}

public void push(int x) {

stack.push(x);

if(minstack.isEmpty()){

minstack.push(x);

return;

}

if(x

minstack.push(x);

}else{

minstack.push(minstack.peek());

}

}

public void pop() {

if(stack.isEmpty()) return;

else{

stack.pop();

minstack.pop();

}

}

public int top() {

if(stack.isEmpty()){

return -1;

}else{

return stack.peek();

}

}

public int min() {

if(stack.isEmpty()) return -1;

return minstack.peek();

}

}

31 栈的压入、弹出序列(辅助栈)

面试题31. 栈的压入、弹出序列 LeetCode 地址

题目描述:

输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的全部数字均不相等。例如,序列 {1,2,3,4,5} 是某栈的压栈序列,序列 {4,5,3,2,1} 是该压栈序列对应的一个弹出序列,但 {4,3,5,1,2} 就不多是该压栈序列的弹出序列。

思路:用辅助栈进行压入、弹出

import java.util.Stack;

class Solution {

public boolean validateStackSequences(int[] pushed, int[] popped) {

if(pushed==null||popped==null) return false;

Stack stack=new Stack<>();

int index=0;

int point=0;

while(index

if(point

stack.push(pushed[point++]);

}else{

break;

}

while(index

stack.pop();

index++;

}

}

while(index

stack.pop();

index++;

}

if(stack.isEmpty()){

return true;

}

return false;

}

}

32 I 从上到下打印二叉树(队列)

面试题32 - I. 从上到下打印二叉树

题目描述:从上到下打印出二叉树的每一个节点,同一层的节点按照从左到右的顺序打印。

import java.util.*;

class Solution {

public int[] levelOrder(TreeNode root) {

int []ret=new int[0];

if(root==null) return ret;

Queue queue=new LinkedList();

ArrayList list=new ArrayList<>();

queue.add(root);

while(!queue.isEmpty()){

TreeNode node=queue.poll();

list.add(node.val);

if(node.left!=null) queue.add(node.left);

if(node.right!=null) queue.add(node.right);

}

ret=new int[list.size()];

for(int i=0;i

ret[i]=list.get(i);

}

return ret;

}

}

相关题目: 广度优先遍历图也是用队列

32 II 从上到下打印二叉树(队列)

题目描述:从上到下按层打印二叉树,同一层的节点按从左到右的顺序打印,每一层打印到一行。

import java.util.*;

class Solution {

public List> levelOrder(TreeNode root) {

List> ret=new ArrayList<>();

if(root==null) return ret;

Queue queue=new LinkedList();

queue.add(root);

while(!queue.isEmpty()){

int len=queue.size();

ArrayList list=new ArrayList<>();

while(len-->0){

TreeNode node=queue.poll();

list.add(node.val);

if(node.left!=null) queue.add(node.left);

if(node.right!=null) queue.add(node.right);

}

ret.add(list);

}

return ret;

}

}

32 III 之字形打印二叉树(两个栈)

import java.util.*;

class Solution {

public List> levelOrder(TreeNode root) {

List> ret=new ArrayList<>();

if(root==null) return ret;

Stack stack1=new Stack<>();//存从左往右的

stack1.push(root);

Stack stack2=new Stack<>();//存从右往左的

while(!stack1.isEmpty()||!stack2.isEmpty()){

ArrayList list=new ArrayList<>();

if(!stack1.isEmpty()){

while(!stack1.isEmpty()){

TreeNode node=stack1.pop();

list.add(node.val);

if(node.left!=null) stack2.push(node.left);

if(node.right!=null) stack2.push(node.right);

}

}else{

while(!stack2.isEmpty()){

TreeNode node=stack2.pop();

list.add(node.val);

if(node.right!=null) stack1.push(node.right);

if(node.left!=null) stack1.push(node.left);

}

}

ret.add(list);

}

return ret;

}

}

33 二叉搜索树的后序遍历序列(递归)

class Solution {

public boolean verifyPostorder(int[] postorder) {

if(postorder==null||postorder.length<1) return true;

return verifyCore(postorder,0,postorder.length-1);

}

public boolean verifyCore(int[] post,int start,int end){

if(start==end) return true;

int root=post[end];

int mid=-1;

for(int i=start;i

if(post[i]>root){

mid=i;

break;

}

}

//判断是否后面的都大于root

if(mid!=-1){

for(int i=mid;i

if(post[i]>root){

continue;

}else{

return false;

}

}

}

if(mid==start) //没有左子树

return verifyCore(post,mid,end-1);

if(mid==-1) //没有右子树

return verifyCore(post,start,end-1);

return verifyCore(post,start,mid-1)&&verifyCore(post,mid,end-1);

}

}

相关题目: 判断是不是前序遍历结果

34 二叉树中和为某一值的路径(回溯)

import java.util.*;

class Solution {

List> ret=new ArrayList<>();

public List> pathSum(TreeNode root, int sum) {

if(root==null) return ret;

ArrayList list=new ArrayList<>();

list.add(root.val);

core(root,list,sum-root.val);

return ret;

}

public void core(TreeNode node,ArrayList list,int sum){

if(node==null) return;

if(node.left==null&&node.right==null){

if(sum==0){

ret.add(new ArrayList(list));

return;

}else{

return;

}

}

if(node.left!=null){

list.add(node.left.val);

core(node.left,list,sum-node.left.val);

list.remove(list.size()-1);

}

if(node.right!=null){

list.add(node.right.val);

core(node.right,list,sum-node.right.val);

list.remove(list.size()-1);

}

}

}

35 复杂链表的复制

class Solution {

public Node copyRandomList(Node head) {

if(head==null) return null;

Node pHead=head;

Node pre=head;

//复制一份连起来 1 1 2 2 3 3

while(head!=null){

Node node=new Node(head.val);

pre=head;

head=head.next;

pre.next=node;

node.next=head;

}

//复制随机节点

head=pHead;

Node node=head.next;

while(head!=null){

node=head.next;

if(head.random==null){

node.random=null;

}else{

node.random=head.random.next;

}

head=node.next;

}

//拆分

head=pHead;

Node top=head.next;

node=head.next;

while(node.next!=null){

head.next=node.next;

head=head.next;

node.next=head.next;

node=node.next;

}

head.next=null;

head=pHead;

return top;

}

}

36 二叉搜索树与双向链表

注意:LeetCode上要求是双向循环链表!!

class Solution {

public Node core(Node root) {

if(root==null||(root.left==null&&root.right==null)) return root;

if(root.left==null&&root.right!=null){

Node rightLeft=core(root.right);

rightLeft.left=root;

root.right=rightLeft;

return root;

}

//左子树最左边的节点

Node left=core(root.left);

Node leftRight=left;

//左子树最右边的节点

while(leftRight.right!=null){

leftRight=leftRight.right;

}

//右子树最左边的节点

Node right=core(root.right);

if(right==null){

root.left=leftRight;

leftRight.right=root;

return left;

}

root.left=leftRight;

root.right=right;

leftRight.right=root;

right.left=root;

return left;

}

public Node treeToDoublyList(Node root) {

if(root==null) return root;

if(root.left==null&&root.right==null){

root.left=root;

root.right=root;

return root;

}

if(root.left==null&&root.right!=null){

Node rightLeft=core(root);

//加上首尾循环

Node rightRight=rightLeft;

while(rightRight.right!=null){

rightRight=rightRight.right;

}

rightRight.right=root;

root.left=rightRight;

return root;

}

Node left=core(root);

Node rightRight=root;

while(rightRight.right!=null){

rightRight=rightRight.right;

}

//加上首尾循环

rightRight.right=left;

left.left=rightRight;

return left;

}

}

37 序列化二叉树(递归)

public class Codec {

// Encodes a tree to a single string.

public String serialize(TreeNode root) {

//序列化成前序遍历结果

//null用*表示 用.间隔

String str="";

if(root==null) return "*,";

str+=root.val+",";

String strLeft=serialize(root.left);

String strRight=serialize(root.right);

str=str+strLeft+strRight;

return str;

}

// Decodes your encoded data to tree.

public TreeNode deserialize(String data) {

String [] cs=data.substring(0,data.length()-1).split(",");

int index[]=new int[1];

index[0]=0;

return core(cs,index);

}

public TreeNode core(String [] cs,int[]index) {

if(cs[index[0]].equals("*")){

index[0]++;

return null;

}else{

TreeNode root=new TreeNode(Integer.valueOf(cs[index[0]]));

index[0]++;

root.left=core(cs,index);

root.right=core(cs,index);

return root;

}

}

}

// Your Codec object will be instantiated and called as such:

// Codec codec = new Codec();

// codec.deserialize(codec.serialize(root));

38 字符串的排列(回溯)

import java.util.*;

class Solution {

List list=new LinkedList<>();

char[] c;

public void core(int x){

if(x==c.length-1){

list.add(String.valueOf(c));

return;

}

HashSet set=new HashSet<>();

for(int i=x;i

if(set.contains(c[i])) continue;

set.add(c[i]);

swap(i,x);//c[i] 固定在第 x 位

core(x+1);

swap(i,x);

}

}

public void swap(int x,int y){

char tmp=c[x];

c[x]=c[y];

c[y]=tmp;

}

public String[] permutation(String s) {

c=s.toCharArray();

core(0);

return list.toArray(new String[list.size()]);

}

}

相关题目:

(1)求字符的全部组合

(2)8个数字放到正方体8个顶点上,使得相对面上顶点和相等

(3)8皇后问题

39 数组中出现次数超过一半的数字

class Solution {

public int majorityElement(int[] nums) {

if(nums==null||nums.length<1) return -1;

int count=0;

int num=nums[0];

for(int i=0;i

if(count==0){

num=nums[i];

count++;

}else{

if(nums[i]==num){

count++;

}else{

count--;

}

}

}

return num;

}

}

40 最小的k个数 (快排/堆)

class Solution {

public int[] getLeastNumbers(int[] arr, int k) {

int[] ret=new int[k];

if(arr==null||arr.length<1) return ret;

quikSort(arr,0,arr.length-1,k);

for(int i=0;i

ret[i]=arr[i];

}

return ret;

}

public void quikSort(int[] arr,int start,int end,int k){

if(start==end) return ;

int low=start;

int high=end;

int stand=arr[start];

while(low

while(low

high--;

arr[low]=arr[high];

while(low

low++;

arr[high]=arr[low];

}

arr[low]=stand;

if(low==k){

return;

}else if(low

quikSort(arr,low+1,end,k);

return;

}else{

quikSort(arr,start,low,k);

return;

}

}

}

方法二:堆

public int[] getLeastNumbers(int[] arr, int k) {

int[] ret=new int[k];

if(arr==null||arr.length<1||k<1) return ret;

//大顶堆

PriorityQueue heap=new PriorityQueue<>(k,new Comparator() {

@Override

public int compare(Integer o1, Integer o2) {

return o2-o1;

}

});

for(int i=0;i

if(heap.size()

heap.offer(arr[i]);

}else{

if(arr[i]

//heap.poll();

heap.remove();

heap.offer(arr[i]);

}

}

}

int index=0;

while(!heap.isEmpty()){

ret[index++]=heap.poll();

}

return ret;

}

41 数据流中的中位数(堆)

import java.util.PriorityQueue;

class MedianFinder {

/** initialize your data structure here. */

PriorityQueue maxHeap;

PriorityQueue minHeap;

public MedianFinder() {

maxHeap=new PriorityQueue<>(new Comparator() {

@Override

public int compare(Integer o1, Integer o2) {

return o2-o1;

}

});

minHeap=new PriorityQueue<>();//默认小顶堆

}

public void addNum(int num) {

//1.保证最小堆比最大堆数多1/0

//2.保证最小堆的数都大于最大堆的对顶

if(maxHeap.size()

if(minHeap.peek()

minHeap.offer(num);

maxHeap.offer(minHeap.poll());

}else{

maxHeap.offer(num);

}

}else{

if(!maxHeap.isEmpty()&&num

maxHeap.offer(num);

minHeap.offer(maxHeap.poll());

}else{

minHeap.offer(num);

}

}

}

public double findMedian() {

if(minHeap.isEmpty()) return -1.0;//没有数据的状况

if(maxHeap.size()

return minHeap.peek();

}else{//总数是偶数

return (maxHeap.peek()+minHeap.peek())/2.0;

}

}

}

42 连续子数组的最大和

class Solution {

public int maxSubArray(int[] nums) {

if(nums==null||nums.length<1) return -1;

int ret=nums[0];

int num=0;

for(int i=0;i

if(num<=0){//加了前面的数小于0,不如不加,从当前数开始

num=nums[i];

}else{

num+=nums[i];

}

if(ret

ret=num;

}

}

return ret;

}

}

43 1~n整数中1出现的次数

class Solution {

public int countDigitOne(int n) {

if(n<=0) return 0;

String s=String.valueOf(n);

return core(s,n);

}

public int core(String s,int n){

if(s==null||s.length()<1)return 0;

int first=Integer.valueOf(String.valueOf(s.charAt(0)));

if(first==0) return 0;

if(s.length()==1&&first>0) return 1;

//21345 numFirst是万位数目

int numFirst=0;

if(first>1)

numFirst=(int)Math.pow(10,s.length()-1);

else numFirst=(n%(int)Math.pow(10,s.length()-1))+1;

//numOther是除了万位以外的1的数目

int numOther=first*(s.length()-1)*(int)Math.pow(10,s.length()-2);

//numRest 是1-1345中的数目

int numRest=core(String.valueOf(n%(int)Math.pow(10,s.length()-1)),n%(int)Math.pow(10,s.length()-1));

return numFirst+numOther+numRest;

}

}

44 数字序列中某一位的数字

class Solution {

public int findNthDigit(int n) {

long nn=n;

int digit=1;

while(true){

long nums=coreNums(digit);//digit位数占多少位

if(nn>nums){

nn=nn-nums;

}else{

n=(int) nn;

//n=811 digit=3

int tmp=n/digit;//270

int ys=n%digit;//1

int base=(int)Math.pow(10,digit-1);//100

if(digit==1) base=0;

int num=base+tmp;//370

int ret=Integer.valueOf(String.valueOf(String.valueOf(num).charAt(ys)));

return ret;

}

digit++;

}

//return -1;

}

public long coreNums(int digit){

if(digit==1) return ((int)Math.pow(10,digit)-0)*digit;

return ((long)Math.pow(10,digit)-(long)Math.pow(10,digit-1))*digit;

}

}

45 把数组排成最小的数(排序规则)

class Solution {

public String minNumber(int[] nums) {

ArrayList list =new ArrayList<>();

for (int i = 0; i < nums.length; i++) {

list.add(String.valueOf(nums[i]));

}

Collections.sort(list,new Comparator() {

@Override

public int compare(String o1, String o2) {

String opt1=o1+o2;

String opt2=o2+o1;

if(opt1.equals(opt2)) return 0;

int len=(o1+o2).length();

boolean flag=false;

for(int i=0;i

if(opt1.charAt(i)

flag=true;

break;

}else if(opt1.charAt(i)>opt2.charAt(i)){

flag=false;

break;

}

}

if(flag){

return -1;

}else{

return 1;

}

}

});

StringBuilder ret=new StringBuilder();

for (int i = 0; i < list.size(); i++) {

ret.append(list.get(i));

}

return ret.toString();

}

}

46 把数字翻译成字符串(动归)

class Solution {

public int translateNum(int num) {

String string=String.valueOf(num);

int dp[]=new int[string.length()+1];

dp[0]=1;

for (int i = 1; i <= string.length(); i++) {

int tmpRet=dp[i-1];

if(i-2>=0){

int tmp=Integer.valueOf(string.substring(i-2,i));

if (10<=tmp&&tmp<=25) {

tmpRet+=dp[i-2];

}

}

dp[i]=tmpRet;

}

return dp[string.length()];

}

}

47 礼物的最大价值(动归)

class Solution {

public int maxValue(int[][] grid) {

int[][]dp=new int[grid.length][grid[0].length];

for (int i = 0; i < dp.length; i++) {

for (int j = 0; j < dp[0].length; j++) {

int opt1=0;

int opt2=0;

if(i-1>=0){

opt1=dp[i-1][j];

}

if(j-1>=0){

opt2=dp[i][j-1];

}

dp[i][j]=Math.max(opt1,opt2)+grid[i][j];

}

}

return dp[grid.length-1][grid[0].length-1];

}

}

方法二:优化,一维动归

class Solution {

public int maxValue(int[][] grid) {

int[]dp=new int[grid[0].length];

for (int i = 0; i < grid.length; i++) {

for (int j = 0; j < grid[0].length; j++) {

int opt1=0;

int opt2=0;

if(i-1>=0){

opt1=dp[j];

}

if(j-1>=0){

opt2=dp[j-1];

}

dp[j]=Math.max(opt1,opt2)+grid[i][j];

}

}

return dp[grid[0].length-1];

}

}

48 最长不含重复字符的子字符串(动归)

class Solution {

public int lengthOfLongestSubstring(String s) {

StringBuilder str=new StringBuilder("");

int len=0;//存以前的值

int ret=0;//存结果,最长的长度

int fromIndex=0;//存上一个字符的index

for (int i = 0; i < s.length(); i++) {

String string=String.valueOf(s.charAt(i));

int index=str.indexOf(string);

if(index==-1){//不存在

str.append(string);

len=str.length();

}else{//存在该字符

int index1=s.indexOf(s.charAt(i), fromIndex);

if(i-index1<=len){//判断上一个当前字符与当前字符之间的距离

str=new StringBuilder(s.substring(index1+1,i+1));

len=str.length();

fromIndex=index1+1;

}

}

ret=Math.max(ret, len);

}

return ret;

}

}

49 丑数

class Solution {

public int nthUglyNumber(int n) {

if(n<=0) return 0;

int[] ret=new int[n];

int index=1;

ret[0]=1;

int t2=0;

int t3=0;

int t5=0;

while(index

int two=ret[t2]*2;

int three=ret[t3]*3;

int five=ret[t5]*5;

//找到最小的 加进去 t++

if(two<=three&&two<=five){

ret[index++]=two;

t2++;

if(two==three) t3++;

if(two==five) t5++;

continue;

}

if(three<=two&&three<=five){

ret[index++]=three;

t3++;

if(two==three) t2++;

if(three==five) t5++;

continue;

}

if(five<=two&&five<=three){

ret[index++]=five;

t5++;

if(five==three) t3++;

if(two==five) t2++;

continue;

}

}

return ret[n-1];

}

}

50 第一个只出现一次的字符(Hash)

class Solution {

public char firstUniqChar(String s) {

int ret[]=new int[256];//存次数的数组

for(int i=0;i

ret[s.charAt(i)]+=1;

}

for(int i=0;i

if(ret[s.charAt(i)]==1){

return s.charAt(i);

}

}

return ' ';

}

}

相关题目:

(1)数据流中的一个只出现的字符

(2)是不是变位词

(3)从第一个字符串中删除第二个字符串中的字母

51 数组中的逆序对(归并)

题目描述:

在数组中的两个数字,若是前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。

class Solution {

public int reversePairs(int[] nums) {

return mergeSort(nums,0,nums.length-1);

}

public int mergeSort(int[]nums,int left,int right){

if(left>=right) return 0;

int mid=(left+right)>>1;

int leftcount=mergeSort(nums,left,mid);

int rightcount=mergeSort(nums,mid+1,right);

int mergecount=merge(nums,left,right);

return leftcount+rightcount+mergecount;

}

public int merge(int nums[],int left,int right){

int count=0,index=0;

int []tmp=new int[right-left+1];

int start=left;

int mid=(left+right)>>1;

int end=mid+1;

while(start<=mid&&end<=right){

if(nums[start]<=nums[end])

tmp[index++]=nums[start++];

else{

tmp[index++]=nums[end++];

count+=mid-start+1;

}

}

while(start<=mid) tmp[index++]=nums[start++];

while(end<=right) tmp[index++]=nums[end++];

for(int i=0;i

nums[i+left]=tmp[i];

return count;

}

}

52 两个链表的第一个公共节点

public class Solution {

public ListNode getIntersectionNode(ListNode headA, ListNode headB) {

//找出len相差多少

ListNode nodeA=headA;

ListNode nodeB=headB;

int lenA=0;

int lenB=0;

while(nodeA!=null){

nodeA=nodeA.next;

lenA++;

}

while(nodeB!=null){

nodeB=nodeB.next;

lenB++;

}

int lenTmp=0;

if(lenA>lenB){

nodeA=headA;

nodeB=headB;

lenTmp=lenA-lenB;

}else{

nodeA=headB;

nodeB=headA;

lenTmp=lenB-lenA;

}

//其中一个先走

while(lenTmp>0){

nodeA=nodeA.next;

lenTmp--;

}

//一块儿遍历

while(nodeA!=nodeB){

nodeA=nodeA.next;

nodeB=nodeB.next;

}

return nodeA;

}

}

53 I 在排序数组中查找数字(二分)

class Solution {

public int search(int[] nums, int target) {

//logn的复杂度

int leftIndex=0;

int start=0;

int end=nums.length-1;

int mid;

//找左侧边界

while(start<=end){

mid=(start+end)>>1;

if(nums[mid]==target){

end=mid-1;

}else if(nums[mid]

start=mid+1;

}else{

end=mid-1;

}

}

if(start>=nums.length||nums[start]!=target)

return 0;

else leftIndex=start;

//找右侧边界

start=0;

end=nums.length-1;

while(start<=end){

mid=(start+end)>>1;

if(nums[mid]==target){

start=mid+1;

}else if(nums[mid]

start=mid+1;

}else{

end=mid-1;

}

}

return end-leftIndex+1;

}

}

53 II 0~n-1中缺失的数字(二分)

class Solution {

public int missingNumber(int[] nums) {

//找到下标和值不相等的元素

int start=0;

int end=nums.length-1;

int mid;

while(start<=end){

mid=(start+end)>>1;

if(nums[mid]!=mid){

end=mid-1;

}else{

start=mid+1;

}

}

return start;

}

}

53III 数组中数值和下标相等的元素(二分)

题目描述:假设一个单调递增的数组里的每一个元素都是整数而且是惟一的。请编程实现一个函数,找出数组中任意一个数值等于其下标的元素。例如,在数组{-3,-1,1,3,5}中,数字3和它的下标相等。

public int findSameNumber(int[] nums) {

//找到下标和值相等的元素

int start=0;

int end=nums.length-1;

int mid;

while(start<=end){

mid=(start+end)>>1;

if(nums[mid]==mid){

return mid;

}else if(nums[mid]

start=mid+1;

}else{

end=mid-1;

}

}

return -1;

54 二叉搜索树的第k大节点(栈)

import java.util.Stack;

class Solution {

public int kthLargest(TreeNode root, int k) {

if(root==null||k<=0) return -1;

//非递归中序遍历 左根右,本题须要右根左

int len=0;

Stack stack=new Stack<>();

TreeNode node=root;

while(!stack.isEmpty()||node!=null){

if(node!=null){

stack.push(node);

node=node.right;

}else{

len++;

if(len==k){

return stack.peek().val;

}

node=stack.pop().left;

}

}

return -1;

}

}

55 I 二叉树的深度

class Solution {

public int maxDepth(TreeNode root) {

if(root==null) return 0;

return Math.max(maxDepth(root.left),maxDepth(root.right))+1;

}

}

55 II 平衡二叉树

方法一:须要重复遍历屡次

class Solution {

public boolean isBalanced(TreeNode root) {

if(root==null) return true;

int tmp=Math.abs(depth(root.left)-depth(root.right));

if(tmp<=1){

return isBalanced(root.left)&&isBalanced(root.right);

}else{

return false;

}

}

public int depth(TreeNode root){

if(root==null) return 0;

return Math.max(depth(root.left),depth(root.right))+1;

}

}

方法二:遍历一次

class Solution {

public boolean isBalanced(TreeNode root) {

if(root==null) return true;

int[]deep=new int[1];

deep[0]=0;

return isBalanced(root,deep);

}

public boolean isBalanced(TreeNode root,int[] deep) {

if(root==null){

deep[0]=0;

return true;

}

int[]left=new int[1];

int[]right=new int[1];

if(isBalanced(root.left,left)&&isBalanced(root.right,right)){

if(Math.abs(left[0]-right[0])<=1){

deep[0]=Math.max(left[0],right[0])+1;

return true;

}

}

return false;

}

}

56 数组中数字出现的次数(异或)

LeetCode地址

题目描述:

一个整型数组 nums 里除两个数字以外,其余数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。

思路:异或

(1)思考数组中有一个出现一次的数字。解决办法是所有异或,由于异或的性质是相同为0,不一样为1,某数与本身异或等于0,0与某数异或等于某数。

(2)在有两个出现一次的数字异或以后,获得a b异或的结果;a b异或的结果必定不为0,由于a b不一样,找到不一样的那个位;再对数组异或,分别获得a 和b

代码:

class Solution {

public int[] singleNumbers(int[] nums) {

int ret[]=new int[2];

if(nums.length<=1) return ret;

//找a b异或以后的结果 mask

int mask=0;

for(int num:nums){

mask=mask^num;

}

//找mask位,第一个为1的位

int bitMask=1;

while((bitMask&mask)==0){

bitMask=bitMask<<1;

}

//找a b

int ret1=0,ret2=0;

for(int i=0;i

if((bitMask&nums[i])==0) ret1=ret1^nums[i];

else ret2=ret2^nums[i];

}

ret[0]=ret1;

ret[1]=ret2;

return ret;

}

}

56 II 数组中数字出现的次数 (位运算)

class Solution {

public int singleNumber(int[] nums) {

int []arr=new int[32];//存每一位的和

int bitMask=1;

for (int i = 0; i < nums.length; i++) {

bitMask=1;

for (int j = arr.length-1; j >=0 ; j--) {

if((bitMask&nums[i])==bitMask)

arr[j]+=1;

bitMask=bitMask<<1;

}

}

int ret=0;

int base=1;

for (int i = arr.length-1; i >=0; i--) {

if(arr[i]%3!=0){

ret+=base;

}

base=base*2;

}

return ret;

}

}

57 和为s的两个数字(双指针)

class Solution {

public int[] twoSum(int[] nums, int target) {

int []ret=new int[2];

int start=0;

int end=nums.length-1;

while(start

if(nums[start]+nums[end]==target){

ret[0]=nums[start];

ret[1]=nums[end];

return ret;

}else if(nums[start]+nums[end]

start++;

}else{

end--;

}

}

return ret;

}

}

57 II 和为s的连续正数序列(双指针)

class Solution {

public int[][] findContinuousSequence(int target) {

ArrayList list=new ArrayList<>();

int start=1;

int end=2;

int sum=3;

while(start

if (sum==target) {

int arr[]=new int[end-start+1];

for (int i = start; i <= end; i++)

arr[i-start]=i;

list.add(arr);

end++;

sum+=end;

}else if(sum

end++;

sum+=end;

}else{

sum-=start;

start++;

}

}

int[][] ret=list.toArray(new int[list.size()][]);

return ret;

}

}

58 I 翻转单词顺序

class Solution {

public String reverseWords(String s) {

StringBuilder sb=new StringBuilder("");

String string=reverse(s);

int index=0;

char []arr=string.toCharArray();

for (int i = 0; i < string.length(); i++) {

if(arr[i]!=' '){

continue;

}else{//不属于字母

String tmp=reverse(string.substring(index,i));

tmp=tmp.trim();

if (!tmp.equals("")) {//处理空格

sb.append(tmp);

sb.append(arr[i]);

index=i+1;

}

}

}

sb.append(reverse(string.substring(index,string.length())));

return sb.toString().trim();

}

public String reverse(String s) {

char[] array=s.toCharArray();

int start=0;

int end=array.length-1;

while(start

//swap

char tmp=array[start];

array[start]=array[end];

array[end]=tmp;

start++;

end--;

}

return String.valueOf(array);

}

}

58 II 左旋转字符串

class Solution {

public String reverseLeftWords(String s, int n) {

if(s==null||n<0||s.length()

String ret="";

//分别翻转

String opt1=reverse(s.substring(0,n));

String opt2=reverse(s.substring(n));

//翻转整个

ret=reverse(opt1+opt2);

return ret;

}

public String reverse(String s) {

char[] array=s.toCharArray();

int start=0;

int end=array.length-1;

while(start

//swap

char tmp=array[start];

array[start]=array[end];

array[end]=tmp;

start++;

end--;

}

return String.valueOf(array);

}

}

59 I 滑动窗口的最大值(双端队列)

class Solution {

public int[] maxSlidingWindow(int[] nums, int k) {

int[]ret=new int[0];

if(nums.length<1||k<1) return ret;

ret=new int[nums.length-k+1];

Deque queue=new LinkedList();

//存有可能成为最大值的 数 的 下标

for (int i = 0; i < k; i++) {

while (!queue.isEmpty()&&nums[queue.getLast()]<=nums[i]) {

queue.pollLast();

}

queue.addLast(i);

}

int index=0;

for (int i = k; i < nums.length; i++) {

ret[index++]=nums[queue.getFirst()];//first端存最大值

while (!queue.isEmpty()&&nums[queue.getLast()]<=nums[i]) {

queue.pollLast();

}

//滑动窗口不包含i数字,已经滑出

if(!queue.isEmpty()&&queue.getFirst()<=(i-k)){

queue.pollFirst();

}

queue.addLast(i);

}

ret[index++]=nums[queue.getFirst()];

return ret;

}

}

59 II 队列的最大值(双端队列)

class MaxQueue {

Deque data;

Deque max;

public MaxQueue() {

data=new LinkedList();

max=new LinkedList();

}

public int max_value() {

if(!max.isEmpty()) return max.getFirst();

else return -1;

}

public void push_back(int value) {

//加到后面

while(!max.isEmpty()&&max.getLast()<=value){

max.pollLast();

}

max.addLast(value);

data.add(value);

}

public int pop_front() {//删除

if(data.isEmpty()){

return -1;

}else{

if(data.peek().intValue()==max.getFirst().intValue()){

max.pollFirst();

}

return data.poll();

}

}

}

60 n个骰子的点数

class Solution {

public double[] twoSum(int n) {

int num=6;//注意程序的扩展性

int lenArr=n*num;

int sumPre[]=new int[lenArr+1];//存和为i的数量 上一轮

int sumNow[]=new int[lenArr+1];//存这轮循环 和为i的数量

int tmp[]=new int[lenArr+1];//

for (int i = 1; i <= num; i++) {

sumPre[i]=1;

sumNow[i]=1;

}

for (int i = 2; i <=n; i++) {

for (int j = 0; j < sumNow.length; j++) {

sumPre[j]=sumNow[j];

sumNow[j]=0;

}

for (int j = i; j <= i*num; j++) {//2..12

int sum=0;

int maxlen=num;

if(j<=6){

maxlen=j-1;

}

for (int k = 1; k <= maxlen; k++) {// 1..6

sum+=sumPre[j-k];

}

sumNow[j]=sum;

}

}

double sumCount=Math.pow(num, n);

double ret[]=new double[lenArr-n+1];

int index=0;

for (int i = n; i <= lenArr; i++) {

ret[index++]=sumNow[i]/sumCount;

}

//Arrays.sort(ret);

return ret;

}

}

61 扑克牌中的顺子

class Solution {

public boolean isStraight(int[] nums) {

//排好序

Arrays.sort(nums);

//找数组中0的个数

int countZero=0;

for (int i = 0; i < nums.length; i++) {

if (nums[i]==0) {

countZero++;

}

}

//找间隙的个数

int gap=0;

for (int i = nums.length-1; i >0; i--) {

if(nums[i-1]==0){

break;

}

int tmp=nums[i]-nums[i-1];

if(tmp==0){

return false;

}else if(tmp>1){

gap+=tmp-1;

}

}

if (gap<=countZero) {

return true;

}

return false;

}

}

62 圆圈中最后剩下的数字

class Solution {

public int lastRemaining(int n, int m) {

if(n==0||m==0) return -1;

int last=0;

for(int i=2;i<=n;i++){

last=(last+m)%i;

}

return last;

}

}

63 股票的最大利润

class Solution {

public int maxProfit(int[] prices) {

int minValue=Integer.MAX_VALUE;//以前i-1个数中最小的值

int ret=0;

for (int i = 0; i < prices.length; i++) {

minValue=Math.min(minValue, prices[i]);

ret=Math.max(ret, prices[i]-minValue);

}

return ret;

}

}

64 求1+2+…+n(逻辑运算)

class Solution {

int ret=0;

public int sumNums(int n) {

boolean flag=n>1&& sumNums(n-1)>0;

ret+=n;

return ret;

}

}

65 不用加减乘除作加法(逻辑运算)

class Solution {

public int add(int a, int b) {

int carry=0;//进位

int sum=0;//和

do {

sum=a^b;

carry=(a&b)<<1;

a=sum;

b=carry;

} while (carry!=0);

return sum;

}

}

66 构建乘积数组

class Solution {

public int[] constructArr(int[] a) {

int ret[]=new int[a.length];

int tmp=1;

for (int i = 0; i < a.length; i++) {

ret[i]=tmp;

tmp*=a[i];

}

tmp=1;

for (int i = ret.length-1; i >=0; i--) {

ret[i]*=tmp;

tmp*=a[i];

}

return ret;

}

}

67 把字符串转换成整数(注意考虑状况完整)

class Solution {

public int strToInt(String str) {

if(str==null||str.length()<1) return 0;

char arr[]=str.trim().toCharArray();

if(arr.length<1) return 0;

int sign=1;

int start=0;

if (arr[0]=='-') {

sign =-1;

start=1;

}else if (arr[0]=='+') {

start=1;

}

long ret=0;

for (int i = start; i < arr.length; i++) {

if (arr[i]'9') {

break;

}

ret=ret*10+arr[i]-'0';

if (ret>Integer.MAX_VALUE) {

if (sign==1) {

return Integer.MAX_VALUE;

}else{

if ((ret*-1)<=Integer.MIN_VALUE) {

return Integer.MIN_VALUE;

}

}

}

}

return sign*(int)ret;

}

}

68 I 二叉搜索树的最近公共祖先(递归)

class Solution {

public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {

if(root==null) return null;

if(p.val

return root;

}

if(p.val

return lowestCommonAncestor(root.left,p,q);

}

if(p.val>root.val&&q.val>root.val){

return lowestCommonAncestor(root.right,p,q);

}

return root;

}

}

68 II 二叉树的最近公共祖先(递归)

class Solution {

public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {

if(root==null||root.val==p.val||root.val==q.val) return root;

TreeNode left=lowestCommonAncestor(root.left,p,q);

TreeNode right=lowestCommonAncestor(root.right,p,q);

if(left!=null&&right!=null) return root;

if(left!=null)

return left;

else return right;

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值