校招必备之剑指offer JAVA 全代码多实现【1~10】
校招必备之剑指offer JAVA 全代码多实现【11~20】
校招必备之剑指offer JAVA 全代码多实现【21~30】
11、题目描述
给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。
保证base和exponent不同时为0
思路1:直接暴力跑。只是需要注意存在指数可能为负,处理一下即可。时间复杂度为O(N),别看虽然是O(N),但是如果是非常大的指数级,仍然需要跑很久。
public class Solution {
public double Power(double base, int exponent) {
if(base==0) return 0;
if(exponent==0) return 1;
double res=1;
if(exponent<0){
base=1/base;
exponent=-exponent;
}
while(exponent>0){
exponent--;
res*=base;
}
return res;
}
}
思路2:快速幂,推荐https://blog.csdn.net/qq_19782019/article/details/85621386这篇文章。时间复杂度大概在O(log2N)
public class Solution {
public double Power(double base, int exponent) {
double res=1;
if(exponent<0){
base=1/base;
exponent=-exponent;
}
while(exponent!=0){
if(exponent%2==1){
res*=base;
}
exponent=exponent>>1;
base*=base;
}
return res;
}
}
12、题目描述
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。
思路1:使用额外空间。用两个队列分别存。时间复杂度O(N) 空间复杂度O(N)
import java.util.ArrayDeque;
import java.util.Deque;
public class Solution {
public void reOrderArray(int [] array) {
if (array == null || array.length == 0) {
return;
}
Deque<Integer> deque1=new ArrayDeque();//存奇数
Deque<Integer> deque2=new ArrayDeque();//存偶数
for(int i:array){
if(i%2==1){
deque1.offer(i);
}else{
deque2.offer(i);
}
}
int i=0;
while(!deque1.isEmpty()){
array[i++]=deque1.poll();
}
while(!deque2.isEmpty()){
array[i++]=deque2.poll();
}
}
}
思路2:类似冒泡排序,从后面找起,找到的第一个偶数依次交换到最后,然后往前遍历。时间复杂度O(N^2),空间复杂度O(1)
import java.util.ArrayDeque;
import java.util.Deque;
public class Solution {
public void reOrderArray(int [] array) {
if (array == null || array.length == 0) {
return;
}
int temp=0;
int count=0;//记录第几个偶数
for(int i=array.length-1;i>=0;i--){
if(array[i]%2==0){
for(int j=i;j<array.length-1-count;j++){
temp=array[j];
array[j]=array[j+1];
array[j+1]=temp;
}
count++;
}
}
}
}
13、题目描述
输入一个链表,输出该链表中倒数第k个结点。
思路1:第一反应。也是比较垃圾的想法。遍历两次O(N)
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}*/
public class Solution {
public ListNode FindKthToTail(ListNode head,int k) {
int count=0;
ListNode cur=head;
while(cur!=null){
cur=cur.next;
count++;
}
ListNode node=head;
if(count<k) return null;
while(count>k){
count--;
node=node.next;
}
return node;
}
}
思路2:别人的想法。只需要遍历一次,用两个指针,一个先走K-1步,然后当先走的到最后时,后面一个则是倒数第k个。
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}*/
public class Solution {
public ListNode FindKthToTail(ListNode head,int k) {
int count=0;
ListNode fast=head;
ListNode slow=head;
while(k>0){
k--;
if(fast!=null){
fast=fast.next;
}else{
return null;
}
}
while(fast!=null){
fast=fast.next;
slow=slow.next;
}
return slow;
}
}
13、题目描述
输入一个链表,反转链表后,输出新链表的表头。
思路1:头插法,新建一个指向null的头结点,然后不断头插。
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}*/
public class Solution {
public ListNode ReverseList(ListNode head) {
if(head==null) return null;
ListNode newhead=null;
ListNode next=head.next;;
while(head.next!=null){
head.next=newhead;
newhead=head;
head=next;
next=next.next;
}
head.next=newhead;
newhead=head;
return newhead;
}
}
思路2:利用栈,先进先出。注意这里需要将最后一个节点指向null,否则最后两个节点循环指向,死循环超时
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}*/
import java.util.*;
public class Solution {
public ListNode ReverseList(ListNode head) {
Stack<ListNode> stack=new Stack<>();
while(head!=null){
stack.push(head);
head=head.next;
}
ListNode newhead=new ListNode(0);
ListNode cur=newhead;
while(!stack.isEmpty()){
cur.next=stack.pop();
cur=cur.next;
}
cur.next=null;
return newhead.next;
}
}
14、题目描述
输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
思路:很简单的一道题,双指针分别比较,然后指向新链表。好像方法就一个。
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}*/
public class Solution {
public ListNode Merge(ListNode list1,ListNode list2) {
ListNode p=list1;
ListNode q=list2;
ListNode newhead=new ListNode(0);
ListNode cur=newhead;
while(p!=null&&q!=null){
if(p.val<q.val){
cur.next=p;
p=p.next;
}else{
cur.next=q;
q=q.next;
}
cur=cur.next;
}
if(p==null){
cur.next=q;
}
if(q==null){
cur.next=p;
}
return newhead.next;
}
}
15、题目描述
输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)
思路:感觉这题还是有一些难的,思考的时候逻辑有些乱了。看了别人的过程才理清。貌似没有第二种解法,本来想先前序遍历输出到一个数组中,然后判断两个数组是否包含关系,后来仔细想想好像不行毙掉了。
首先判断子结构而不是子树,所谓子树,以代码注释中的为例, 以2 、3 为根节点的是这个大树的子树。而2、3的子树不是大树的子树。子结构就是包含关系,2、3的子树可以是1的子结构。简而言之,子树一定是子结构,子结构不一定是子树。
我们判断是否是子结构,可以通过以下步骤,
1)首先判断根节点是否相同,如果不同,肯定不是子结构。
2)如果相同,那么递归左右节点。
重复1)2)直到B被遍历完,如果A先遍历完,而B未遍历完,则不是子结构。
/**
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
1
2 3
4 5 6 7
8 9
}
*/
import java.util.*;
public class Solution {
public boolean HasSubtree(TreeNode root1,TreeNode root2) {
if(root2==null||root1==null) return false;
boolean res=false;
if(root1.val==root2.val){//如果找到相同的根节点,就以此遍历进行查找比较,返回结果
res=judge(root1,root2);
}
if(!res){//如果判断不相同,则以左右节点继续寻找下一个相同的节点
res=HasSubtree(root1.left,root2)||HasSubtree(root1.right,root2);
}
return res;
}
public boolean judge(TreeNode A,TreeNode B){
if(B==null) return true;//B要在前,因为我们关心B是否能遍历完,如果遍历完就说明能。如果A在前,
//出现一种情况,A、B同时遍历完,应该判断true,但由于A在前返回false
if(A==null) return false;
if(A.val!=B.val) return false;
return judge(A.left,B.left)&&judge(A.right,B.right);
}
}
16、题目描述
操作给定的二叉树,将其变换为源二叉树的镜像。
思路:递归交换左右节点。好像别的方法都大同小异,没啥区别。
/**
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
import java.util.*;
public class Solution {
public void Mirror(TreeNode root) {
if(root==null) return;
exChange(root);
}
public void exChange(TreeNode parent){
if(parent==null) return;
TreeNode left=parent.left;
TreeNode right=parent.right;
if(left==null&&right==null) return;
parent.left=right;
parent.right=left;
exChange(left);
exChange(right);
}
}
17、题目描述
输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.
思路:这题其实细节蛮多的,一不小心就出错。设置四个边界,然后每次跑一趟,将对应边界缩小。注意一个细节,必须手动先将下一次运动的变量
import java.util.*;
/*
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
*/
public class Solution {
public ArrayList<Integer> printMatrix(int [][] matrix) {
ArrayList<Integer> list=new ArrayList<>();
int m=matrix.length;
if(m==0) return list;
int n=matrix[0].length;
int v=0,h=0;//下界
int i=0,j=0;//坐标
while(i>=h&&j>=v&&i<m&&j<n){
while(j<n){
list.add(matrix[i][j++]);
}
h++;
j--;
i++;//此处必须先加1,然后和边缘判断,否则的话会再往回重复打印一遍
if(i>=m) break;
while(i<m){
list.add(matrix[i++][j]);
}
m--;
i--;
j--;
if(j<v) break;
while(j>=v){
list.add(matrix[i][j--]);
}
n--;
j++;
i--;
if(i<h) break;
while(i>=h){
list.add(matrix[i--][j]);
}
v++;
i++;
j++;
if(j>=n) break;
}
return list;
}
}
思路2:找机会补充一下。方法好像蛮多的,但是这题好麻烦,不想做了。有机会再补
18、题目描述
定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。
思路:用两个栈,一个栈正常存数,另一个栈用来存历史的最小数。
import java.util.Stack;
public class Solution {
Stack<Integer> stack1=new Stack<>();
Stack<Integer> stack2=new Stack<>();
public void push(int node) {
stack1.push(node);
if(!stack2.isEmpty()){
if(stack2.peek()>node){
stack2.push(node);
}
}else stack2.push(node);
}
public void pop() {
int x=stack1.pop();
if(stack2.peek()==x){
stack2.pop();
}
}
public int top() {
return stack1.peek();
}
public int min() {
return stack2.peek();
}
}
19、题目描述
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)
思路:用双指针,分别指向入栈序列和出栈序列。如果所指元素不相等,则说明入栈,直到入栈序列跑完,如果相等就说明入栈后立即出栈。
接下来跑出栈序列,如果出栈序列的元素,不等于栈内元素,则说明不是对应的出栈序列。方法都差不多。
import java.util.*;
public class Solution {
public boolean IsPopOrder(int [] pushA,int [] popA) {
Stack<Integer> stack=new Stack<>();
int n=pushA.length-1;
int j=0;
for(int i=0;i<=n;i++){
if(pushA[i]!=popA[j]){
stack.push(pushA[i]);
}else j++;
}
while(j<=n){
if(popA[j++]!=stack.pop()){
return false;
}
}
return true;
}
}
20、题目描述
从上往下打印出二叉树的每个节点,同层节点从左至右打印。
思路:其实就是层次遍历,每一行从上到下依次打印。借用队列的bfs。
import java.util.*;
/**
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public ArrayList<Integer> PrintFromTopToBottom(TreeNode root) {
Queue<TreeNode> queue=new LinkedList<>();
ArrayList<Integer> res=new ArrayList<>();
if(root==null) return res;
queue.offer(root);
while(!queue.isEmpty()){
int len=queue.size();
while(len>0){
len--;
TreeNode node=queue.poll();
res.add(node.val);
if(node.left!=null) queue.offer(node.left);
if(node.right!=null) queue.offer(node.right);
}
}
return res;
}
}