文章目录
从尾到头打印链表
链表从头到尾存入数组,数组逆序输出
(1)引入辅助数组
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
ArrayList<Integer> arr = new ArrayList<Integer>();
ArrayList<Integer> arr1 = new ArrayList<Integer>();
while(listNode!=null){
arr.add(listNode.val);
listNode = listNode.next;
}
for(int i=arr.size()-1;i>=0;i--){
arr1.add(arr.get(i));
}
return arr1;
}
}
(2)Collections的reverse方法
/**
* public class ListNode {
* int val;
* ListNode next = null;
*
* ListNode(int val) {
* this.val = val;
* }
* }
*
*/
import java.util.Collections;
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
ArrayList<Integer> arr = new ArrayList<Integer>();
while(listNode!=null){
arr.add(listNode.val);
listNode = listNode.next;
}
Collections.reverse(arr);
return arr;
}
}
递归
import java.util.ArrayList;
public class Solution {
ArrayList<Integer> arr = new ArrayList<Integer>();
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
if(listNode !=null) {
printListFromTailToHead(listNode.next);
arr.add(listNode.val);
}
return arr;
}
}
栈
import java.util.ArrayList;
import java.util.Stack;
public class Solution {
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
Stack<Integer> a = new Stack<Integer>();
while(listNode !=null) {
a.push(listNode.val);
listNode = listNode.next;
}
ArrayList<Integer> arr = new ArrayList<Integer>();
while(!a.isEmpty()) {
arr.add(a.pop());
}
return arr;
}
}
重建二叉树
已知前序,中序,重建二叉树(假设前序和中序都不含重复数字)
我的递归
public class RecontrustBinaryTree {
public static TreeNode reConstructBinaryTree(int [] pre,int [] in) {
if(pre ==null || in == null)
return null;
if(pre.length==0 || in.length==0)
return null ;
int root = pre[0];
if(pre.length == 1){
// System.out.println(root);
return new TreeNode(root);
}
ArrayList<Integer> left = new ArrayList<Integer>();
int j = 0;
int count_left = 0;
for(int i=0;i< in.length;i++){
if(in[i]!=root) {
left.add(in[i]);
count_left++;
}
else{
j= i;
break;
}
}
int count_right = 0;
ArrayList<Integer> right = new ArrayList<Integer>();
for(int k=j+1;k< in.length;k++){
right.add(in[k]);
count_right++;
}
ArrayList<Integer> pre_left = new ArrayList<Integer>();
ArrayList<Integer> pre_right = new ArrayList<Integer>();
for(int i = 1;i<pre.length;i++) {
if(count_left!=0) {
pre_left.add(pre[i]);
count_left --;
}else {
pre_right.add(pre[i]);
}
}
// System.out.println(pre_left);
// System.out.println(pre_right);
// System.out.println(left);
// System.out.println(right);
int[] a = ArraytoInt(pre_left);
int[] b = ArraytoInt(pre_right);
int[] c = ArraytoInt(left);
int[] d = ArraytoInt(right);
TreeNode result = new TreeNode(root);
result.left = reConstructBinaryTree(a,c);
result.right = reConstructBinaryTree(b,d);
// System.out.println(root);
return result;
}
public static void main(String[] args) {
int [] pre = {1,2,4,7,3,5,6,8};
int [] in = {4,7,2,1,5,3,8,6};
TreeNode re = reConstructBinaryTree(pre,in);
printPostOrder(re);
}
public static int[] ArraytoInt(ArrayList<Integer> l) {
int[] res = new int[l.size()];
for(int i=0;i<l.size();i++) {
res[i] = l.get(i);
}
return res;
}
//递归后续遍历
public static void printPostOrder(TreeNode root) {
if (root != null) {
printPostOrder(root.left);
printPostOrder(root.right);
System.out.println(root.val);
}
}
}
大神的递归
链接:https://www.nowcoder.com/questionTerminal/8a19cbe657394eeaac2f6ea9b0f6fcf6
来源:牛客网
public class Solution {
public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
TreeNode root=reConstructBinaryTree(pre,0,pre.length-1,in,0,in.length-1);
return root;
}
//前序遍历{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6}
private TreeNode reConstructBinaryTree(int [] pre,int startPre,int endPre,int [] in,int startIn,int endIn) {
if(startPre>endPre||startIn>endIn)
return null;
TreeNode root=new TreeNode(pre[startPre]);
for(int i=startIn;i<=endIn;i++)
if(in[i]==pre[startPre]){
root.left=reConstructBinaryTree(pre,startPre+1,startPre+i-startIn,in,startIn,i-1);
root.right=reConstructBinaryTree(pre,i-startIn+startPre+1,endPre,in,i+1,endIn);
break;
}
return root;
}
}
栈和队列
两个栈实现队列
一个栈(如stack1)只能用来存,另一个栈(如stack2)只能用来取
当取元素时首先检查stack2是否为空,如果不空直接stack2.pop(),否则将stack1中的元素全部倒入stack2,如果倒入之后stack2仍为空则需要抛异常,否则stack2.pop()。
import java.util.Stack;
public class Solution {
Stack<Integer> stack1 = new Stack<Integer>();
Stack<Integer> stack2 = new Stack<Integer>();
public void push(int node) {
stack1.push(node);
}
public int pop() {
if(stack2.isEmpty()){
while(!stack1.isEmpty()){
stack2.push(stack1.pop());
}
}
return stack2.pop();
}
}
两个队列实现栈
leetcode225
压栈压入q1,如a,b,c.
弹栈时候,先把a,b删除并放入q2,再删去c,然后再把q2和q1交换。
取top元素:压栈的x和弹栈时候q1.poll().
判断是否为空,即判断q1
import java.util.*;
class MyStack {
private Queue<Integer> q1;
private Queue<Integer> q2;
private int top;
/** Initialize your data structure here. */
public MyStack() {
q1 = new LinkedList<Integer>();
q2 = new LinkedList<Integer>();
}
/** Push element x onto stack. */
public void push(int x) {
q1.add(x);
top = x;
}
/** Removes the element on top of the stack and returns that element. */
public int pop() {
while(q1.size()>1) {
top = q1.poll();
q2.add(top);
}
int re = q1.poll();
Queue<Integer> temp = q1;
q1 = q2;
q2 = temp;
return re;
}
/** Get the top element. */
public int top() {
return top;
}
/** Returns whether the stack is empty. */
public boolean empty() {
return q1.isEmpty();
}
}
最小栈
最大栈
定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。
辅助栈每次存之前的最小元素和新压入栈的最小值
public class Solution {
Stack<Integer> s1 = new Stack<Integer>();
Stack<Integer> s2 = new Stack<Integer>();
int min = Integer.MAX_VALUE;
public void push(int node) {
s1.push(node);
if(node < min)
min = node;
s2.push(min);
}
public void pop() {
s1.pop();
s2.pop();
}
public int top() {
return s1.peek();
}
public int min() {
return s2.peek();
}
}
栈
栈的压入弹出序列
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。
分析:引入辅助栈,以栈的压入序列 1,2,3,4,5为例:
对于序列4,5,3,2,1:
先压入1,1 ≠ 4;继续压入2,2≠ 4;继续压入3,3≠ 4;继续压入4,4=4;
此时辅助栈里面是1,2,3,4,弹出4,辅助栈为 1,2,3。
接下来看辅助栈栈顶是不是等于5,不等于5,继续压栈5,此时进入while循环,3,2,1与弹出序列的顺序一样。
对于序列4,3,5,1,2,先压入1,1 ≠ 4;继续压入2,2≠ 4;继续压入3,3≠ 4;继续压入4,4=4;
此时辅助栈里面是1,2,3,4,弹出4,辅助栈为 1,2,3。
弹出3,压入5再弹出,此时辅助栈为1,2,栈顶为2.而弹出序列为1,2.
1 ≠ 2,跳出while循环及for循环,此时辅助栈不为空,所以不可能是弹出序列。
public class Solution {
public boolean IsPopOrder(int [] pushA,int [] popA) {
if(pushA.length ==0 || popA.length ==0)
return false;
Stack<Integer> helper = new Stack<Integer>();
int index = 0;
for(Integer t : pushA) {
helper.push(t);
while(!helper.isEmpty() && helper.peek() == popA[index]) {
helper.pop();
index++;
}
}
return helper.isEmpty();
}
}
旋转数组
旋转数组的最小数组
按照剑指offer的思路,两个指针:类似二分查找,循环结束条件是两个指针相邻;
mid == 左 == 右,顺序查找;
public class Solution {
public int minNumberInRotateArray(int [] array) {
if(array == null || array.length == 0)
return 0;
if(array[0] < array[array.length - 1])
return array[0];
else if(array[0] == array[array.length - 1] && array[0] == array[(array.length - 1)/2]) {
//顺序查找,遍历
int min = Integer.MAX_VALUE;
for (int i = 0; i < array.length; i++) {
if(array[i] < min) {
min = array[i];
}
}
return min;
}
else{
int index1 = 0;
int index2 = array.length - 1;
int mid = (index1 + index2)/2;
while(index1 != index2 - 1) {
if(array[mid] >= array[index1]) {
index1 = mid;
}else {
index2 = mid;
}
mid = (index1 + index2)/2;
}
return array[index2];
}
}
}
牛客上其他人的做法,跟二分查找比较类似
链接:https://www.nowcoder.com/questionTerminal/9f3231a991af4f55b95579b44b7a01ba
来源:牛客网
public class Solution {
public int minNumberInRotateArray(int [] array) {
int low = 0 ; int high = array.length - 1;
while(low < high){
int mid = low + (high - low) / 2;
if(array[mid] > array[high]){
low = mid + 1;
}else if(array[mid] == array[high]){
high = high - 1;
}else{
high = mid;
}
}
return array[low];
}
}
循环升序数组,找数n
二分
注意等号
class Solution {
public int search(int[] nums, int target) {
int index1 = 0;
int index2 = nums.length -1;
while(index1 < index2) {
int mid = index1 + (index2 - index1)/2;
if(nums[mid] == target)
return mid;
//nums[index1] <= nums[mid],不能漏掉等号
else if(nums[index1] <= nums[mid] && (target > nums[mid] || target< nums[index1])) {
index1 = mid + 1;
}else if(nums[index1] > nums[mid] && target > nums[mid] && target< nums[index1]) {
index1 = mid + 1;
}else {
index2 = mid;
}
}
return index2 == index1 && nums[index1] == target ? index1 : -1;
}
}
二分和递归:
将数组一分为二,其中一定有一个是有序的,另一个可能是有序,也能是部分有序。此时有序部分用二分法查找。无序部分再一分为二,其中一个一定有序,另一个可能有序,可能无序。就这样循环.
class Solution {
public static int search(int[] nums, int target) {
return search( nums, 0, nums.length -1, target);
}
//递归来做
private static int search(int[] nums, int low, int high, int target) {
if(low > high)
return -1;
int mid = low + (high - low)/2;
if(nums[mid] == target)
return mid;
if(nums[mid] < nums[high]) {
if(nums[mid] < target && target <= nums[high])
return search( nums, mid+1, high, target);
else
return search( nums, low, mid -1, target);
}else {
//nums[low] <= target 等号不要漏掉
if(nums[low] <= target && target < nums[mid])
return search( nums, low, mid -1, target);
else
return search( nums, mid +1, high, target);
}
}
}
逆序/顺序 螺旋输出数组
顺时针
import java.util.ArrayList;
public class Solution {
public static ArrayList<Integer> printMatrix(int [][] matrix) {
int rows = matrix.length ;
int columns = matrix[0].length;
if(matrix == null || rows == 0 || columns == 0)
return null;
int start = 0;
ArrayList<Integer> res = new ArrayList<Integer>();
while(rows > start*2 && columns > start*2) {
ArrayList<Integer> re = printMatrixClockwise(matrix,rows, columns,start);
start ++;
res.addAll(re);
}
return res;
}
public static ArrayList<Integer> printMatrixClockwise(int [][] matrix,int rows,int columns,int start) {
ArrayList<Integer> res = new ArrayList<Integer>();
int endX = columns -1 - start;
int endY = rows -1- start;
//从左到右,每个圈必打印这一步
for (int i = start; i <= endX; i++) {
int num = matrix[start][i];
res.add(num);
}
//第二步,从右到下,条件是终止行号大于起始行号
if(start < endY) {
for(int i = start +1;i<= endY;i++) {
int num = matrix[i][endX];
res.add(num);
}
}
//第三步,从右到左,条件是终止行号大于起始行号并且终止列号要大于起始列号
if(start < endY && start < endX) {
for(int i = endX-1;i>= start;i--) {
int num = matrix[endY][i];
res.add(num);
}
}
//第四步,从下到上,条件是必须三行两列,即终止行号比起始行号大2并且终止列号要大于起始列号
if(start < endY -1 && start < endX){
for(int i = endY-1;i>= start + 1;i--) {
int num = matrix[i][start];
res.add(num);
}
}
return res;
}
}
java ArrayList 中 add 与addAll的区别
下面有两个List,我想将第二个List的数据添加到第一个List当中,用add方法的话是这样添加的:
for(String item : list2){
list1.add(item);
}
如果使用addAll的话:
list1.addAll(list2);
也可以定义要添加的位置,可以用addAll(int index, Collection<?>);
逆时针
public class PrintMatrixAnticlockwise {
public static ArrayList<Integer> printMatrix(int [][] matrix) {
int rows = matrix.length ;
int columns = matrix[0].length;
if(matrix == null || rows == 0 || columns == 0)
return null;
int start = 0;
ArrayList<Integer> res = new ArrayList<Integer>();
while(rows > start*2 && columns > start*2) {
ArrayList<Integer> re = printMatrixClockanti(matrix,rows, columns,start);
start ++;
res.addAll(re);
}
return res;
}
public static ArrayList<Integer> printMatrixClockanti(int [][] matrix,int rows,int columns,int start) {
ArrayList<Integer> res = new ArrayList<Integer>();
int endX = columns -1 - start;
int endY = rows -1- start;
//从上到下,每个圈必打印这一步
for(int i = start;i<= endY;i++) {
int num = matrix[i][start];
res.add(num);
}
if(start < endX){
//从左到右
for (int i = start+1; i <= endX; i++) {
int num = matrix[endY][i];
res.add(num);
}
}
//从下到上
if(start < endY && start < endX) {
for(int i = endY-1;i>= start;i--) {
int num = matrix[i][endX];
res.add(num);
}
}
//从右到左
if(start < endY && start < endX -1){
for(int i = endX-1;i>= start +1;i--) {
int num = matrix[start][i];
res.add(num);
}
}
return res;
}
}
数值的整数次方
- 1.全面考察指数的正负、底数是否为零等情况。
- 2.写出指数的二进制表达,例如13表达为二进制1101。
- 3.优化:右移代表除以2,位运算代替取余
递归
public class Solution {
public double Power(double base, int exponent) {
if(base == 0 && exponent< 0)
throw new RuntimeException();
if(base == 0)
return 0;
if(base == 1 || exponent == 0)
return 1;
int n = exponent;
if(exponent < 0)
n = - exponent;
double res = Power(base,n>>1);
res *= res;
if((n & 1) ==1)
res *= base;
if(exponent < 0)
return 1/res;
else
return res;
}
}
不用递归,直接判断
public double Power(double base, int exponent) {
if(base == 0 && exponent< 0)
throw new RuntimeException();
if(base == 0)
return 0;
if(base == 1 || exponent == 0)
return 1;
int n = Math.abs(exponent);
double res = 1;
if((n & 1) ==1)
res = base;
while(n != 0) {
n = n>>1;
res *= base;
}
if(exponent < 0)
return 1/res;
else
return res;
}
链表的倒数第k个结点
思想:两个指针,其中一个比另一个快k-1步
**鲁棒: 空链表或者k=0
链表长度小于k
**
public ListNode FindKthToTail(ListNode head,int k) {
if(head == null || k ==0)
return null;
ListNode p1 = head;
ListNode p2 = head;
int i = 0;
while(p1 != null) {
if(i >= k)
p2 = p2.next;
p1 = p1.next;
i++;
}
return i>=k ? p2:null;
}
链表
反转链表
非递归
public ListNode ReverseList(ListNode head) {
if(head == null || head.next == null)
return head;
ListNode current = head;
ListNode pre = null;
ListNode ne = null;
while(current != null) {
ne = current.next;
current.next = pre;
pre = current;
current = ne;
}
return pre;
}
递归
private ListNode reverse(ListNode head){
if (head == null || head.next == null)
return head;
ListNode temp = head.next;//保存下一个节点
ListNode newHead = reverse(head.next);//整体思维,宏观语义
temp.next = head;//连上头与递归部分
head.next = null;//调整尾部
return newHead;//返回头节点
}
————————————————
版权声明:本文为CSDN博主「小胖FWC」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u010651249/article/details/90247595
这是递归压栈到最后一个元素,设置一个存储变量,记录新链表的头节点(原链表的尾节点。。。)Rev_head。
然后将4弹出,现在head指向3, 代码是:head->next->next = head; head->next = NULL;
该节点head为3 head->next->next = head将4的next指向3,这里要注意,修改了指向后,原链表指向还存在,需要删除,所以有head->next = NULL; 依照这样的思路一直递归到1,返回之前记录的Rev_head
————————————————
版权声明:本文为CSDN博主「djxnsiwbfk」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Wu_ye123/article/details/88729736
合并有序链表
这个在瓜子二面就写过,是一个白板直接敲代码
非递归
public ListNode Merge(ListNode list1,ListNode list2) {
if(list1 == null)
return list2;
if(list2 == null)
return list1;
ListNode list3 = new ListNode(-1);
ListNode head = list3;
while(list1 != null && list2 != null) {
if(list1.val <= list2.val) {
list3.next = list1;
list1 = list1.next;
}else {
list3.next = list2;
list2 = list2.next;
}
list3 = list3.next;
}
if(list1 != null)
list3.next = list1;
if(list2 != null)
list3.next = list2;
return head.next;
}
易错点:
1.list3要初始化 ListNode list3 = new ListNode(-1);
2.要重新定义一个链表等于list3,因为list3的指针会一直向后移动
3.list3 = list3.next; 不要忘记,不仅仅list1和list2的指针在动,list3的指针也在动。
树
树的子结构
链接:https://www.nowcoder.com/questionTerminal/6e196c44c7004d15b1610b9afca8bd88
来源:牛客网
public class Solution {
/第一部分,递归看子树根节点是否相等
public static boolean HasSubtree(TreeNode root1, TreeNode root2) {
boolean result = false;
//当Tree1和Tree2都不为零的时候,才进行比较。否则直接返回false
if (root2 != null && root1 != null) {
//如果找到了对应Tree2的根节点的点
if(root1.val == root2.val){
//以这个根节点为为起点判断是否包含Tree2
result = doesTree1HaveTree2(root1,root2);
}
//如果找不到,那么就再去root的左儿子当作起点,去判断时候包含Tree2
if (!result) {
result = HasSubtree(root1.left,root2);
}
//如果还找不到,那么就再去root的右儿子当作起点,去判断时候包含Tree2
if (!result) {
result = HasSubtree(root1.right,root2);
}
}
//返回结果
return result;
}
//第二部分,判断左右子树是否相同
public static boolean doesTree1HaveTree2(TreeNode node1, TreeNode node2) {
//如果Tree2已经遍历完了都能对应的上,返回true
if (node2 == null) {
return true;
}
//如果Tree2还没有遍历完,Tree1却遍历完了。返回false
if (node1 == null) {
return false;
}
//如果其中有一个点没有对应上,返回false
if (node1.val != node2.val) {
return false;
}
//如果根节点对应的上,那么就分别去子节点里面匹配
return doesTree1HaveTree2(node1.left,node2.left) && doesTree1HaveTree2(node1.right,node2.right);
}
二叉树的镜像
递归
二叉树的前序遍历,如果遍历到的节点有子节点,则交换它的两个子节点。
public void Mirror(TreeNode root) {
if(root == null)
return;
if(root.left == null && root.right == null)
return;
TreeNode tmp = root.left;
root.left = root.right;
root.right = tmp;
if(root.left != null)
Mirror(root.left);
if(root.right != null)
Mirror(root.right);
}
非递归
- 栈
public void Mirror(TreeNode root) {
//栈
if(root == null)
return;
if(root.left == null && root.right == null)
return;
Stack<TreeNode> s = new Stack<>();
s.push(root);
while(s.size() >0) {
TreeNode p = s.pop();
TreeNode tmp = p.left;
p.left = p.right;
p.right = tmp;
if(p.left != null)
s.push(p.left);
if(p.right != null)
s.push(p.right);
}
}