面试题21:调整数组顺序使奇数位于偶数前面
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param array int整型一维数组
* @return int整型一维数组
*/
public int[] reOrderArray (int[] array) {
// write code here
int left = 0;
int right = array.length - 1;
int temp = 0;
while(left < right){
if(array[left] % 2 == 0){
if(array[right] % 2 == 1){
temp = array[left];
array[left] = array[right];
array[right] = temp;
left++;
right--;
}else{
right--;
}
}else {
left++;
}
}
return array;
}
}
import java.util.*;
public class Solution {
public int[] reOrderArray (int[] array) {
int n = array.length;
int[] res = new int[n];
//统计奇数个数
int odd = 0;
//遍历统计
for(int i = 0; i < n; i++){
if(array[i] % 2 == 1)
odd++;
}
//x与y分别表示答案中奇偶数的坐标
int x = 0, y = odd;
for(int i = 0; i < n; i++){
//奇数在前
if(array[i] % 2 == 1){
res[x] = array[i];
x++;
//偶数在后
}else{
res[y] = array[i];
y++;
}
}
return res;
}
}
面试题22:链表中倒数第k个节点
//自己写的
import java.util.*;
/*
* public class ListNode {
* int val;
* ListNode next = null;
* public ListNode(int val) {
* this.val = val;
* }
* }
*/
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param pHead ListNode类
* @param k int整型
* @return ListNode类
*/
public ListNode FindKthToTail (ListNode pHead, int k) {
// write code here
int count = 0;
ListNode originPhead = pHead;
while(pHead != null){
pHead = pHead.next;
count++;
}
if(count < k){
pHead = null;
return pHead;
}
int index = count - k + 1;
count = 1;
while(count < index){
originPhead = originPhead.next;
count++;
}
return originPhead;
}
}
//标准答案
import java.util.*;
public class Solution {
public ListNode FindKthToTail (ListNode pHead, int k) {
int n = 0;
ListNode p = pHead;
//遍历链表,统计链表长度
while(p != null){
n++;
p = p.next;
}
//长度过小,返回空链表
if(n < k)
return null;
p = pHead;
//遍历n-k次
for(int i = 0; i < n - k; i++)
p = p.next;
return p;
}
}
import java.util.*;
public class Solution {
public ListNode FindKthToTail (ListNode pHead, int k) {
int n = 0;
ListNode fast = pHead;
ListNode slow = pHead;
//快指针先行k步
for(int i = 0; i < k; i++){
if(fast != null)
fast = fast.next;
//达不到k步说明链表过短,没有倒数k
else
return slow = null;
}
//快慢指针同步,快指针先到底,慢指针指向倒数第k个
while(fast != null){
fast = fast.next;
slow = slow.next;
}
return slow;
}
}
public Node middleNode(){
//当fast的速度是slow速度的两倍时,当fast走到最后一个节点时,slow出于中间位置。
Node fast=head;
Node slow=head;
while(fast!=null&&fast.next!=null){
fast=fast.next.next;
slow=slow.next;
}
return slow;
}
面试题23:链表中环的入口节点
public class Solution {
//判断有没有环,返回相遇的地方
public ListNode hasCycle(ListNode head) {
//先判断链表为空的情况
if(head == null)
return null;
//快慢双指针
ListNode fast = head;
ListNode slow = head;
//如果没环快指针会先到链表尾
while(fast != null && fast.next != null){
//快指针移动两步
fast = fast.next.next;
//慢指针移动一步
slow = slow.next;
//相遇则有环,返回相遇的位置
if(fast == slow)
return slow;
}
//到末尾说明没有环,返回null
return null;
}
public class Solution {
//判断有没有环,返回相遇的地方
public ListNode hasCycle(ListNode head) {
//先判断链表为空的情况
if(head == null)
return null;
//快慢双指针
ListNode fast = head;
ListNode slow = head;
//如果没环快指针会先到链表尾
while(fast != null && fast.next != null){
//快指针移动两步
fast = fast.next.next;
//慢指针移动一步
slow = slow.next;
//相遇则有环,返回相遇的位置
if(fast == slow)
return slow;
}
//到末尾说明没有环,返回null
return null;
}
public ListNode EntryNodeOfLoop(ListNode pHead) {
ListNode slow = hasCycle(pHead);
//没有环
if(slow == null)
return null;
//快指针回到表头
ListNode fast = pHead;
//再次相遇即是环入口
while(fast != slow){
fast = fast.next;
slow = slow.next;
}
return slow;
}
}
再次相遇的地方就是环的入口
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public ListNode EntryNodeOfLoop(ListNode pHead)
{
if(pHead == null){
return null;
}
// 1.判断链表中有环
ListNode l=pHead,r=pHead;
boolean flag = false;
while(r != null && r.next!=null){
l=l.next;
r=r.next.next;
if(l==r){
flag=true;
break;
}
}
if(!flag){
return null;
}else{
// 2.得到环中节点的数目
int n=1;
r=r.next;
while(l!=r){
r=r.next;
n++;
}
// 3.找到环中的入口节点
//先让一个指针走环的长度,然后两个相遇的地方就是环的入口
l=r=pHead;
for(int i=0;i<n;i++){
r=r.next;
}
while(l!=r){
l=l.next;
r=r.next;
}
return l;
}
}
}
面试题24:反转链表
最开始使用单链表无法解决
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}*/
import java.util.Stack;
public class Solution {
public ListNode ReverseList(ListNode head) {
Stack<ListNode> stack= new Stack<>();
//把链表节点全部摘掉放到栈中
while (head != null) {
stack.push(head);
head = head.next;
}
if (stack.isEmpty())
return null;
ListNode node = stack.pop();
ListNode dummy = node;
//栈中的结点全部出栈,然后重新连成一个新的链表
while (!stack.isEmpty()) {
ListNode tempNode = stack.pop();
node.next = tempNode;
node = node.next;
}
//最后一个结点就是反转前的头结点,一定要让他的next等于空,否则会构成环
node.next = null;
return dummy;
}
}
时间复杂度:O(n),空间复杂度:O(n)
public ListNode ReverseList(ListNode head) {
//新链表
ListNode newHead = null;
while (head != null) {
//先保存访问的节点的下一个节点,保存起来
//留着下一步访问的
ListNode temp = head.next;
//每次访问的原链表节点都会成为新链表的头结点,
//其实就是把新链表挂到访问的原链表节点的
//后面就行了
head.next = newHead;
//更新新链表
newHead = head;
//重新赋值,继续访问
head = temp;
}
//返回新链表
return newHead;
}
public ListNode reverseList(参数0) {
if (终止条件)
return;
逻辑处理(可能有,也可能没有,具体问题具体分析)
//递归调用
ListNode reverse = reverseList(参数1);
逻辑处理(可能有,也可能没有,具体问题具体分析)
}
if (head == null || head.next == null)
return head;
public ListNode ReverseList(ListNode head) {
//终止条件
if (head == null || head.next == null)
return head;
//保存当前节点的下一个结点
ListNode next = head.next;
//从当前节点的下一个结点开始递归调用
ListNode reverse = ReverseList(next);
//reverse是反转之后的链表,因为函数reverseList
// 表示的是对链表的反转,所以反转完之后next肯定
// 是链表reverse的尾结点,然后我们再把当前节点
//head挂到next节点的后面就完成了链表的反转。
next.next = head;
//这里head相当于变成了尾结点,尾结点都是为空的,
//否则会构成环
head.next = null;
return reverse;
}
public ListNode ReverseList(ListNode head) {
if (head == null || head.next == null)
return head;
ListNode reverse = ReverseList(head.next);
head.next.next = head;
head.next = null;
return reverse;
}
public ListNode ReverseList(ListNode head) {
return reverseListInt(head, null);
}
private ListNode reverseListInt(ListNode head, ListNode newHead) {
if (head == null)
return newHead;
ListNode next = head.next;
head.next = newHead;
return reverseListInt(next, head);
}
public ListNode ReverseList(ListNode head) {
return reverseListInt(head, null);
}
private ListNode reverseListInt(ListNode head, ListNode newHead) {
if (head == null)
return newHead;
ListNode next = head.next;
head.next = newHead;
ListNode node = reverseListInt(next, head);
return node;
}
面试题25:合并两个排序的链表
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}*/
public class Solution {
public ListNode Merge(ListNode list1,ListNode list2) {
if(list1==null){
return list2;
}
else if(list2==null){
return list1;
}
if(list2.val>list1.val){
list1.next = Merge(list1.next,list2);
return list1;
}
else{
list2.next = Merge(list1,list2.next);
return list2;
}
}
}
public class Solution {
public ListNode Merge(ListNode list1,ListNode list2) {
ListNode dummy = new ListNode(-1);
ListNode res = dummy;
// 必须保证两个list都不为空
while(list1 != null & list2 != null) {
if(list1.val > list2.val) {
dummy.next = list2;
list2 = list2.next;
dummy = dummy.next;
} else if(list1.val <= list2.val) {
dummy.next = list1;
list1 = list1.next;
dummy = dummy.next;
}
}
// list1后面还有,就把剩下的全部拿走
if(list1 != null) {
dummy.next = list1;
}
if(list2 != null) {
dummy.next = list2;
}
//因为最后的到的链表要返回出去,所以空间复杂度为O(1)
return res.next;
}
}
面试题26:树的字结构
树一般要注意递归思想的应用
/**
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
/*思路:参考剑指offer
1、首先设置标志位result = false,因为一旦匹配成功result就设为true,
剩下的代码不会执行,如果匹配不成功,默认返回false
2、递归思想,如果根节点相同则递归调用DoesTree1HaveTree2(),
如果根节点不相同,则判断tree1的左子树和tree2是否相同,
再判断右子树和tree2是否相同
3、注意null的条件,HasSubTree中,如果两棵树都不为空才进行判断,
DoesTree1HasTree2中,如果Tree2为空,则说明第二棵树遍历完了,即匹配成功,
tree1为空有两种情况(1)如果tree1为空&&tree2不为空说明不匹配,
(2)如果tree1为空,tree2为空,说明匹配。
*/
public class Solution {
public boolean HasSubtree(TreeNode root1,TreeNode root2) {
boolean result = false;
if(root1 != null && root2 != null){
if(root1.val == root2.val){
result = DoesTree1HaveTree2(root1,root2);
}
if(!result){result = HasSubtree(root1.left, root2);}
if(!result){result = HasSubtree(root1.right, root2);}
}
return result;
}
public boolean DoesTree1HaveTree2(TreeNode root1,TreeNode root2){
if(root1 == null && root2 != null) return false;
if(root2 == null) return true;
if(root1.val != root2.val) return false;
return DoesTree1HaveTree2(root1.left, root2.left)
&& DoesTree1HaveTree2(root1.right, root2.right);
}
}
if(!root)
return true/false;
if(!root->left)
return true/false/递归函数;
if(!root->right)
return true/false/递归函数;
面试题27:二叉树的镜像
import java.util.*;
/*
* 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 TreeNode Mirror (TreeNode pRoot) {
//空树返回
if(pRoot == null)
return null;
//先递归子树
TreeNode left = Mirror(pRoot.left);
TreeNode right = Mirror(pRoot.right);
//交换
pRoot.left = right;
pRoot.right = left;
return pRoot;
}
}
import java.util.*;
/*
* 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 TreeNode Mirror (TreeNode pRoot) {
//空树
if(pRoot == null)
return null;
//辅助栈
Stack<TreeNode> s = new Stack<TreeNode>();
//根节点先进栈
s.push(pRoot);
while (!s.isEmpty()){
TreeNode node = s.pop();
//左右节点入栈
if(node.left != null)
s.push(node.left);
if(node.right != null)
s.push(node.right);
//交换左右
TreeNode temp = node.left;
node.left = node.right;
node.right = temp;
}
return pRoot;
}
}
面试题28:对称的二叉树
/*
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
boolean recursion(TreeNode root1, TreeNode root2){
//可以两个都为空
if(root1 == null && root2 == null)
return true;
//只有一个为空或者节点值不同,必定不对称
if(root1 == null || root2 == null || root1.val != root2.val)
return false;
//每层对应的节点进入递归比较
return recursion(root1.left, root2.right)
&& recursion(root1.right, root2.left);
}
boolean isSymmetrical(TreeNode pRoot) {
return recursion(pRoot, pRoot);
}
}
//从左往右加入队列
q1.offer(left.left);
q1.offer(left.right);
//从右往左加入队列
q2.offer(right.right);
q2.offer(right.left);
/*
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 {
boolean isSymmetrical(TreeNode pRoot) {
//空树为对称的
if(pRoot == null)
return true;
//辅助队列用于从两边层次遍历
Queue<TreeNode> q1 = new LinkedList<TreeNode>();
Queue<TreeNode> q2 = new LinkedList<TreeNode>();
q1.offer(pRoot.left);
q2.offer(pRoot.right);
while(!q1.isEmpty() && !q2.isEmpty()){
//分别从左边和右边弹出节点
TreeNode left = q1.poll();
TreeNode right = q2.poll();
//都为空暂时对称
if(left == null && right == null)
continue;
//某一个为空或者数字不相等则不对称
if(left == null || right == null || left.val != right.val)
return false;
//从左往右加入队列
q1.offer(left.left);
q1.offer(left.right);
//从右往左加入队列
q2.offer(right.right);
q2.offer(right.left);
}
//都检验完都是对称的
return true;
}
}
面试题29:顺时针打印矩阵
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> printMatrix(int [][] matrix) {
ArrayList<Integer> res = new ArrayList<>();
//先排除特殊情况
if(matrix.length == 0) {
return res;
}
//左边界
int left = 0;
//右边界
int right = matrix[0].length - 1;
//上边界
int up = 0;
//下边界
int down = matrix.length - 1;
//直到边界重合
while(left <= right && up <= down){
//上边界的从左到右
for(int i = left; i <= right; i++)
res.add(matrix[up][i]);
//上边界向下
up++;
if(up > down)
break;
//右边界的从上到下
for(int i = up; i <= down; i++)
res.add(matrix[i][right]);
//右边界向左
right--;
if(left > right)
break;
//下边界的从右到左
for(int i = right; i >= left; i--)
res.add(matrix[down][i]);
//下边界向上
down--;
if(up > down)
break;
//左边界的从下到上
for(int i = down; i >= up; i--)
res.add(matrix[i][left]);
//左边界向右
left++;
if(left > right)
break;
}
return res;
}
}
面试题30:包含min函数的栈
//最开始的写法,时间复杂度 O(n) 空间复杂度 O(n),不满足要求
import java.util.Stack;
public class Solution {
Stack minStack = new Stack();
public void push(int node) {
minStack.push(node);
}
public void pop() {
minStack.pop();
}
public int top() {
return (int)minStack.get(0);
}
public int min() {
int[] arr = new int[100];
int min = -10001;
while(!minStack.empty()){
if(min > (int)minStack.pop()){
min = (int)minStack.pop();
}
}
return min;
}
}
//空或者新元素较小,则入栈
if(s2.isEmpty() || s2.peek() > node)
s2.push(node);
else
//重复加入栈顶
s2.push(s2.peek());
import java.util.Stack;
public class Solution {
//用于栈的push 与 pop
Stack<Integer> s1 = new Stack<Integer>();
//用于存储最小min
Stack<Integer> s2 = new Stack<Integer>();
public void push(int node) {
s1.push(node);
//空或者新元素较小,则入栈
if(s2.isEmpty() || s2.peek() > node)
s2.push(node);
else
//重复加入栈顶
s2.push(s2.peek());
}
public void pop() {
s1.pop();
s2.pop();
}
public int top() {
return s1.peek();
}
public int min() {
return s2.peek();
}
}