双重检验懒汉式单例模式
// 懒汉式(线程安全,同步方法)
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;
}
}
LeetCode地址
题目描述:
在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
思路:
(1)HashSet找重复数字
(2)数组交换,利用 0~n-1这个条件,类似位图的思想。边排序边判断。
代码:
class Solution {
public int findRepeatNumber(int[] nums) {
for(int i=0;i<nums.length;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;
}
}
考虑另外一种情况,如果不允许交换数组中元素,如何解决?
方法一:
import java.util.*;
class Solution {
public int findRepeatNumber(int[] nums) {
HashSet<Integer> set=new HashSet<>();
for(int i=0;i<nums.length;i++){
if(set.contains(nums[i]))
return nums[i];
else set.add(nums[i]);
}
return -1;
}
}
LeetCode地址
题目描述:
在一个 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<matrix.length){
if(matrix[i][j]==target){
return true;
}else if(matrix[i][j]<target){
i++;
}else{
j--;
}
}
return false;
}
}
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<arr.length;i++){
if(arr[i]==' '){
ret.append("%20");
}else{
ret.append(arr[i]);
}
}
return ret.toString();
}
}
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<ListNode> 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;
}
}
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<inorder.length;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;
}
}
牛客网地址
题目描述:
给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
思路:判断是否有右子树
/*
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;
}
}
}
LeetCode地址
题目描述:
用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead ,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead 操作返回 -1 )
思路:
方法一,stack1始终存放压入队列的正序,stack2来倒换数据
方法二,对方法一改进,判断stack2如果为空再把stack1导入进来,stack2不为空直接返回栈顶元素
方法一:
import java.util.Stack;
class CQueue {
Stack<Integer> stack1;
Stack<Integer> 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<Integer> stack1;
Stack<Integer> 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();
}
}
}
相关题目:
225.用队列实现栈
232.用栈实现队列
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<n-1;i++){
ret=(opt1+opt2)%1000000007;
opt1=opt2;
opt2=ret;
}
return ret;
}
}
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<n-1;i++){
ret=(opt1+opt2)%1000000007;
opt1=opt2;
opt2=ret;
}
return ret;
}
}
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<numbers.length;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<right&&(right-left!=1)){
mid=(left+right)>>1;
//无法判断有序
if(numbers[mid]==numbers[right]){
right--;
continue;
}//无法判断有序
if(numbers[mid]==numbers[left]){
left++;
continue;
}
if(numbers[mid]<numbers[right]){
right=mid;
}else if(numbers[left]<numbers[mid]){
left=mid;
}
}
return Math.min(numbers[left],numbers[right]);
}
}
LeetCode地址
题目描述:
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。
class Solution {
public boolean exist(char[][] board, String word) {
for(int i=0;i<board.length;i++){
for(int j=0;j<board[0].length;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;
}
}
}
}
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.length;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;
}
}
}
LeetCode地址
题目描述:
给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]…k[m] 。请问 k[0]k[1]…*k[m] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、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<n+1;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;
}
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,
那么 a^11为:
修改求幂函数为:
//快速幂
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;
}
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的情况,
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的位数
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;
}
}
}
LeetCode地址
题目描述:
输入数字 n,按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3,则打印出 1、2、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.length;i++){
ret[i]=len;
len++;
}
return ret;
}
}
相关题目:考虑大数的情况,解决办法:用字符串存大数
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
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<p.length()&&p.charAt(pointp+1)=='*'){
//判断当前是否是. 或者相等
if((points<s.length()&&p.charAt(pointp)=='.')||
(points<s.length()&&s.charAt(points)==p.charAt(pointp))){
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<s.length()&&(s.charAt(points)==p.charAt(pointp)||p.charAt(pointp)=='.')){
return matchCore(s,p,points+1,pointp+1);
}
return false;
}
}
LeetCode 地址
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<s.length()&&index!=-1){//判断是否是e
//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<s.length()&&index!=-1){//判断是否是e
//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<s.length()){
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<s.length();i++){
if(!Character.isDigit(s.charAt(i))){
return false;
}
}
return true;
}
}
LeetCode地址
class Solution {
public int[] exchange(int[] nums) {
if(nums==null) return null;
int low=0;
int high=nums.length-1;
while(low<high){
while(low<high&&(nums[low]&1)==1)
low++;
while(low<high&&(nums[high]&1)==0)
high--;
int tmp=nums[low];
nums[low]=nums[high];
nums[high]=tmp;
}
return nums;
}
}
面试题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;
}
}
142. 环形链表 II LeetCode
题目描述:
给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
说明:不允许修改给定的链表。
方法一:Hashset
Set<ListNode> 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. 反转链表 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. 合并两个排序的链表 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<l2.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;
}
}
相关题目: 23.合并K个排序链表
面试题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. 二叉树的镜像 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;
}
}
LeetCode地址
题目描述:
请实现一个函数,用来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样,那么它是对称的。
/**
* 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);
}
}
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;
}
}
LeetCode地址
题目描述:
定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 min、push 及 pop 的时间复杂度都是 O(1)。
import java.util.Stack;
class MinStack {
/** initialize your data structure here. */
Stack<Integer> stack;
Stack<Integer> 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.peek()){
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. 栈的压入、弹出序列 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<Integer> stack=new Stack<>();
int index=0;
int point=0;
while(index<popped.length){
if(point<pushed.length){
stack.push(pushed[point++]);
}else{
break;
}
while(index<popped.length&&!stack.isEmpty()&&popped[index]==stack.peek()){
stack.pop();
index++;
}
}
while(index<popped.length&&!stack.isEmpty()&&popped[index]==stack.peek()){
stack.pop();
index++;
}
if(stack.isEmpty()){
return true;
}
return false;
}
}
面试题32 - I. 从上到下打印二叉树
题目描述:从上到下打印出二叉树的每个节点,同一层的节点按照从左到右的顺序打印。
import java.util.*;
class Solution {
public int[] levelOrder(TreeNode root) {
int []ret=new int[0];
if(root==null) return ret;
Queue<TreeNode> queue=new LinkedList<TreeNode>();
ArrayList<Integer> 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<list.size();i++){
ret[i]=list.get(i);
}
return ret;
}
}
相关题目: 广度优先遍历图也是用队列
LeetCode地址
题目描述:从上到下按层打印二叉树,同一层的节点按从左到右的顺序打印,每一层打印到一行。
import java.util.*;
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> ret=new ArrayList<>();
if(root==null) return ret;
Queue<TreeNode> queue=new LinkedList<TreeNode>();
queue.add(root);
while(!queue.isEmpty()){
int len=queue.size();
ArrayList<Integer> 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. 从上到下打印二叉树 III
import java.util.*;
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> ret=new ArrayList<>();
if(root==null) return ret;
Stack<TreeNode> stack1=new Stack<>();//存从左往右的
stack1.push(root);
Stack<TreeNode> stack2=new Stack<>();//存从右往左的
while(!stack1.isEmpty()||!stack2.isEmpty()){
ArrayList<Integer> 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<end;i++){
if(post[i]>root){
mid=i;
break;
}
}
//判断是否后面的都大于root
if(mid!=-1){
for(int i=mid;i<end;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<List<Integer>> ret=new ArrayList<>();
public List<List<Integer>> pathSum(TreeNode root, int sum) {
if(root==null) return ret;
ArrayList<Integer> list=new ArrayList<>();
list.add(root.val);
core(root,list,sum-root.val);
return ret;
}
public void core(TreeNode node,ArrayList<Integer> 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;
}
}
LeetCode 面试题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<String> list=new LinkedList<>();
char[] c;
public void core(int x){
if(x==c.length-1){
list.add(String.valueOf(c));
return;
}
HashSet<Character> set=new HashSet<>();
for(int i=x;i<c.length;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<nums.length;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.length;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<high){
while(low<high&&stand<=arr[high])
high--;
arr[low]=arr[high];
while(low<high&&arr[low]<=stand)
low++;
arr[high]=arr[low];
}
arr[low]=stand;
if(low==k){
return;
}else if(low<k){
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<Integer> heap=new PriorityQueue<>(k,new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2-o1;
}
});
for(int i=0;i<arr.length;i++){
if(heap.size()<k){
heap.offer(arr[i]);
}else{
if(arr[i]<heap.peek()){
//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<Integer> maxHeap;
PriorityQueue<Integer> minHeap;
public MedianFinder() {
maxHeap=new PriorityQueue<>(new Comparator<Integer>() {
@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()<minHeap.size()){//总数奇数
if(minHeap.peek()<num){
minHeap.offer(num);
maxHeap.offer(minHeap.poll());
}else{
maxHeap.offer(num);
}
}else{
if(!maxHeap.isEmpty()&&num<maxHeap.peek()){//num比最大堆的堆顶小
maxHeap.offer(num);
minHeap.offer(maxHeap.poll());
}else{
minHeap.offer(num);
}
}
}
public double findMedian() {
if(minHeap.isEmpty()) return -1.0;//没有数据的情况
if(maxHeap.size()<minHeap.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<nums.length;i++){
if(num<=0){//加了前面的数小于0,不如不加,从当前数开始
num=nums[i];
}else{
num+=nums[i];
}
if(ret<num){
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<String> list =new ArrayList<>();
for (int i = 0; i < nums.length; i++) {
list.add(String.valueOf(nums[i]));
}
Collections.sort(list,new Comparator<String>() {
@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<len;i++){
if(opt1.charAt(i)<opt2.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<n){
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. 第一个只出现一次的字符
class Solution {
public char firstUniqChar(String s) {
int ret[]=new int[256];//存次数的数组
for(int i=0;i<s.length();i++){
ret[s.charAt(i)]+=1;
}
for(int i=0;i<s.length();i++){
if(ret[s.charAt(i)]==1){
return s.charAt(i);
}
}
return ' ';
}
}
相关题目:
(1)数据流中的一个只出现的字符
(2)是否是变位词
(3)从第一个字符串中删除第二个字符串中的字母
LeetCode地址
题目描述:
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
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<tmp.length;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. 在排序数组中查找数字 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]<target){
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]<target){
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;
}
}
题目描述:假设一个单调递增的数组里的每个元素都是整数并且是唯一的。请编程实现一个函数,找出数组中任意一个数值等于其下标的元素。例如,在数组{-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]<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<TreeNode> 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;
}
}
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<nums.length;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. 数组中数字出现的次数 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<end){
if(nums[start]+nums[end]==target){
ret[0]=nums[start];
ret[1]=nums[end];
return ret;
}else if(nums[start]+nums[end]<target){
start++;
}else{
end--;
}
}
return ret;
}
}
面试题57 - II. 和为s的连续正数序列
class Solution {
public int[][] findContinuousSequence(int target) {
ArrayList<int[]> list=new ArrayList<>();
int start=1;
int end=2;
int sum=3;
while(start<end){
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<target){
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<end){
//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()<n) return s;
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<end){
//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<Integer> queue=new LinkedList<Integer>();
//存有可能成为最大值的 数 的 下标
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<Integer> data;
Deque<Integer> max;
public MaxQueue() {
data=new LinkedList<Integer>();
max=new LinkedList<Integer>();
}
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]<'0'||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<root.val&&root.val<q.val){
return root;
}
if(p.val<root.val&&q.val<root.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;
}
}