1.输入一个链表,反转链表后,输出新链表的表头。
package com.csu.marden;
public class Demo1 {
public static void main(String[] args) {
Node head=new Node();
Node node1=new Node(1);
Node node2=new Node(2);
Node node3=new Node(3);
head.next=node1;
node1.next=node2;
node2.next=node3;
show(head);
System.out.println("-------------------------------------------");
show(reverse(head));
}
public static void show(Node head){
Node temp=head.next;
while(temp!=null){
System.out.println(temp.value);
temp=temp.next;
}
}
//链表反转
public static Node reverse(Node head){
Node temp=head.next;
Node newhead=new Node();
while(temp!=null){
//将temp节点摘下来
head.next=temp.next;
//将temp节点插入新表头节点后
temp.next=newhead.next;
newhead.next=temp;
temp=head.next;
}
head.next=newhead.next;
return head;
}
}
class Node{
int value;
Node next;
public Node(int value) {
super();
this.value = value;
}
public Node() {
super();
}
}
2.设计LRU缓存结构,该结构在构造时确定大小,假设大小为K,并有如下两个功能:
- set(key, value):将记录(key, value)插入该结构
- get(key):返回key对应的value值
[要求]
- set和get方法的时间复杂度为O(1)
- 某个key的set或get操作一旦发生,认为这个key的记录成了最常使用的。
- 当缓存的大小超过K时,移除最不经常使用的记录,即set或get最久远的。
若opt=1,接下来两个整数x, y,表示set(x, y)
若opt=2,接下来一个整数x,表示get(x),若x未出现过或已被移除,则返回-1
对于每个操作2,输出一个答案
示例:
输入:[[1,1,1],[1,2,2],[1,3,2],[2,1],[1,4,4],[2,2]],3
输出:[1,-1]
说明:
第一次操作后:最常使用的记录为("1", 1)
第二次操作后:最常使用的记录为("2", 2),("1", 1)变为最不常用的
第三次操作后:最常使用的记录为("3", 2),("1", 1)还是最不常用的
第四次操作后:最常用的记录为("1", 1),("2", 2)变为最不常用的
第五次操作后:大小超过了3,所以移除此时最不常使用的记录("2", 2),加入记录("4", 4),并且为最常使用的记录,然后("3", 2)变为最不常使用的记录
package com.csu.marden;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
public class Demo1 {
public static void main(String[] args) {
int [][] arr={{1,1,1},{1,2,2},{1,3,2},{2,1},{1,4,4},{2,2}};
int k=3;
show(LRU(arr, k));
}
public static void show(int [] arr){
for(int i=0;i<arr.length;i++){
System.out.println(arr[i]);
}
}
public static int[] LRU (int[][] operators, int k) {
//使用数据结构HashMap和Queue
HashMap<Integer,Integer> map=new HashMap<>();
LinkedList<Integer> queue=new LinkedList<>();
List<Integer> list=new ArrayList<>();
for(int i=0;i<operators.length;i++){
//判断当前执行哪个操作
//当前执行写操作
if(operators[i].length==3 && operators[i][0]==1){
//判断当前缓存容量是否达到上限,即是否可以插入数据
if(map.size()<k){
map.put(operators[i][1], operators[i][2]);
queue.addLast(operators[i][1]);
}else{
//首先删除队列头元素,再插入相应的元素节点
int temp=queue.removeFirst();
map.remove(temp);
map.put(operators[i][1], operators[i][2]);
}
}
//当前执行读操作
if(operators[i].length==2 && operators[i][0]==2){
//判断当前读取的key是否存在
if(map.containsKey(operators[i][1])){
list.add(map.get(operators[i][1]));
//出队列,重新入队
queue.remove((Object)operators[i][1]);
queue.addLast(operators[i][1]);
}else{
list.add(-1);
}
}
}
int [] arr=new int [list.size()];
for(int i=0;i<arr.length;i++){
arr[i]=list.get(i);
}
return arr;
}
}
3.请实现有重复数字的有序数组的二分查找。
输出在数组中第一个大于等于查找值的位置,如果数组中不存在这样的数,则输出数组长度加一。
示例:
输出:5,4,[1,2,4,4,5]
输出:3
package com.csu.marden;
public class Demo3 {
public static void main(String[] args) {
int n=5;
int v=4;
int [] a={1,2,4,4,5};
System.out.println(upper_bound_(n, v, a));
}
public static int upper_bound_ (int n, int v, int[] a) {
if(n==0){
return 1;
}
int start=0;
int end=n-1;
while(start<=end){
int mid=(start+end)/2;
if(a[mid]>=v){
if(mid==start || a[mid-1]<v){
return mid+1;
}else{
end=mid-1;
}
}else{
start=mid+1;
}
}
return n+1;
}
}
二分查找的递归和非递归实现:
//非递归版本
public static int binarySearch(int [] arr,int target,int start,int end){
while(start<=end){
int mid=(start+end)/2;
if(arr[mid]==target){
return mid;
}else if(arr[mid]<target){
start=mid+1;
}else{
end=mid-1;
}
}
return -1;
}
//递归版本
public static int binarySearch1(int [] arr,int target,int start,int end){
//递归结束条件
if(start>end){
return -1;
}
int mid=(start+end)/2;
if(arr[mid]==target){
return mid;
}else if(arr[mid]>target){
return binarySearch(arr, target, start, mid-1);
}else{
return binarySearch(arr, target, mid+1, end);
}
}
4.分别按照二叉树先序,中序和后序打印所有的节点。
package com.csu.marden;
public class Demo4 {
public static void main(String[] args) {
TreeNode root=new TreeNode(1);
TreeNode node1=new TreeNode(2);
TreeNode node2=new TreeNode(3);
root.left=node1;
root.right=node2;
threeOrders(root);
}
public static void threeOrders (TreeNode root) {
showPre(root);
System.out.println("---------------");
showMid(root);
System.out.println("---------------");
showAft(root);
System.out.println("---------------");
}
public static void showPre(TreeNode root){
if(root==null){
return;
}else{
System.out.println(root.value);
showPre(root.left);
showPre(root.right);
}
}
public static void showMid(TreeNode root){
if(root==null){
return;
}else{
showPre(root.left);
System.out.println(root.value);
showPre(root.right);
}
}
public static void showAft(TreeNode root){
if(root==null){
return;
}else{
showPre(root.left);
showPre(root.right);
System.out.println(root.value);
}
}
}
class TreeNode{
int value;
TreeNode left;
TreeNode right;
public TreeNode(int value) {
super();
this.value = value;
}
public TreeNode() {
super();
}
}
非递归先序遍历:
package com.csu.marden;
import java.util.Stack;
public class Demo5 {
public static void main(String[] args) {
TreeNode root=new TreeNode(1);
TreeNode node1=new TreeNode(2);
TreeNode node2=new TreeNode(3);
root.left=node1;
root.right=node2;
showPreOrder(root);
}
//非递归先序遍历
public static void showPreOrder(TreeNode root){
Stack<TreeNode> stack=new Stack<>();
if(root!=null){
//将根节点入栈
stack.push(root);
//将栈顶元素出栈,分别将其右节点和左节点入栈
while(stack.size()>0){
TreeNode temp=stack.pop();
System.out.println(temp.value);
if(temp.right!=null){
stack.push(temp.right);
}
if(temp.left!=null){
stack.push(temp.left);
}
}
}
}
}
非递归中序遍历:
public static void showMidOrder(TreeNode root){
Stack<TreeNode> stack=new Stack<>();
//将根节点入栈
stack.push(root);
TreeNode temp=root.left;
//while循环包含入栈条件(左节点存在则入栈)和出栈条件(栈不为空)
while(temp!=null || stack.size()>0){
//入栈
if(temp!=null){
stack.push(temp);
temp=temp.left;
}else{ //出栈
temp=stack.pop();
System.out.println(temp.value);
temp=temp.right;
}
}
}
非递归后序遍历:
对于任一结点P,将其入栈,然后沿其左子树一直往下搜索,直到搜索到没有左孩子的结点,此时该结点出现在栈顶,但是此时不能将其出栈并访问, 因此其右孩子还为被访问。所以接下来按照相同的规则对其右子树进行相同的处理,当访问完其右孩子时,该结点又出现在栈顶,此时可以将其出栈并访问。这样就 保证了正确的访问顺序。可以看出,在这个过程中,每个结点都两次出现在栈顶,只有在第二次出现在栈顶时,才能访问它。因此需要多设置一个变量标识该结点是 否是第一次出现在栈顶。
/*
对于任一结点P,将其入栈,然后沿其左子树一直往下搜索,直到搜索到没有左孩子的结点,
此时该结点出现在栈顶,但是此时不能将其出栈并访问, 因此其右孩子还为被访问。
所以接下来按照相同的规则对其右子树进行相同的处理,当访问完其右孩子时,
该结点又出现在栈顶,此时可以将其出栈并访问。这样就 保证了正确的访问顺序。
可以看出,在这个过程中,每个结点都两次出现在栈顶,只有在第二次出现在栈顶时,才能访问 它。因此需要多设置一个变量标识该结点是 否是第一次出现在栈顶。
*/
public static void showAftOrder(TreeNode root){
Stack<TreeNode> stack=new Stack<>();
//使用map记录每个节点被访问的次数
Map<TreeNode,Integer> map=new HashMap<>();
TreeNode temp=root;
while(temp!=null || stack.size()>0){
if(temp!=null){
stack.push(temp);
map.put(temp, 1);
temp=temp.left;
}else{
temp=stack.peek();
if(map.get(temp)==2){
System.out.println(stack.pop().value);
temp=null;
}else{
map.put(temp, 2);
temp=temp.right;
}
}
}
}
5.判断给定的链表中是否有环(空间复杂度O(1)的解法)
//使用快慢指针判断链表是否有环
public static boolean hasCycle1(ListNode head) {
if(head==null || head.next==null){
return false;
}
ListNode slow=head;
ListNode fast=head.next;
while(slow!=fast){
//指针为null,则说明链表无环
if(fast==null || fast.next==null){
return false;
}else{
slow=slow.next;
fast=fast.next.next;
}
}
return true;
}
6.将两个有序的链表合并为一个新链表,要求新的链表是通过拼接两个链表的节点来生成的。
package com.csu.marden;
public class Demo7 {
public static void main(String[] args) {
ListNode l1=new ListNode();
ListNode node1=new ListNode(2);
ListNode node2=new ListNode(5);
ListNode node3=new ListNode(8);
l1.next=node1;
node1.next=node2;
node2.next=node3;
ListNode l2=new ListNode();
ListNode node11=new ListNode(1);
ListNode node22=new ListNode(4);
ListNode node33=new ListNode(7);
ListNode node44=new ListNode(24);
l2.next=node11;
node11.next=node22;
node22.next=node33;
node33.next=node44;
show(mergeTwoLists(l1, l2));
}
public static void show(ListNode head){
ListNode temp=head.next;
while(temp!=null){
System.out.println(temp.value);
temp=temp.next;
}
}
//带头节点的链表
public static ListNode mergeTwoLists (ListNode l1, ListNode l2) {
ListNode newhead=new ListNode();
ListNode temp1=l1.next;
ListNode temp2=l2.next;
ListNode last=newhead;
while(temp1!=null && temp2!=null){
if(temp1.value<=temp2.value){
//将temp1摘下
l1.next=temp1.next;
//将temp1插入到新节点之后
temp1.next=null;
last.next=temp1;
last=temp1;
temp1=l1.next;
}else{
//将temp2摘下
l2.next=temp2.next;
//将temp2插入到新节点之后
temp2.next=null;
last.next=temp2;
last=temp2;
temp2=l2.next;
}
}
if(temp1!=null && temp2==null){
last.next=temp1;
}
if(temp2!=null && temp1==null){
last.next=temp2;
}
return newhead;
}
}
7.有一个整数数组,请你根据快速排序的思路,找出数组中第K大的数。
给定一个整数数组a,同时给定它的大小n和要找的K(K在1到n之间),请返回第K大的数,保证答案存在。
package com.csu.marden;
public class Demo8 {
public static void main(String[] args) {
int [] arr={1,3,5,8,19,45};
int K=3;
System.out.println(findKth(arr, arr.length, K));
}
//寻找第k大的元素
public static int findKth(int[] a, int n, int K) {
return quickSort(a, K, 0, n-1);
}
public static int quickSort(int [] arr,int k,int start,int end){
if(start>end){
return -1;
}
int i=start;
int j=end;
int base=arr[start];
while(i<j){
while(i<j && arr[j]>=base){
j--;
}
while(i<j && arr[i]<=base){
i++;
}
if(i<j){
int temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
}
//i=j
arr[start]=arr[i];
arr[i]=base;
if(i==arr.length-k){
return arr[i];
}else if(i<arr.length-k){
return quickSort(arr,k,i+1,end);
}else{
return quickSort(arr,k,start,i-1);
}
}
}
8.给定一个链表,删除链表的倒数第n个节点并返回链表的头指针
package com.csu.marden;
public class Demo9 {
public static void main(String[] args) {
ListNode head=new ListNode(1);
ListNode node2=new ListNode(2);
ListNode node3=new ListNode(3);
ListNode node4=new ListNode(4);
ListNode node5=new ListNode(5);
head.next=node2;
node2.next=node3;
node3.next=node4;
node4.next=node5;
int n=2;
show(head);
System.out.println("---------------------------");
show(removeNthFromEnd(head, n));
}
public static void show(ListNode head){
ListNode temp=head;
while(temp!=null){
System.out.println(temp.value);
temp=temp.next;
}
}
//不带头节点
public static ListNode removeNthFromEnd (ListNode head, int n) {
if(head!=null){
//保证n一定有效,即链表的长度大于等于n
//如果要删除的节点在第一个位置
if(n==getLength(head)){
return head.next;
}
else{
ListNode temp=head;
int count=0;
while(count!=getLength(head)-n-1){
count++;
temp=temp.next;
}
//此时temp指向待删除节点的前一个位置
temp.next=temp.next.next;
return head;
}
}
return head;
}
public static int getLength(ListNode head){
ListNode temp=head;
int count=0;
while(temp!=null){
count++;
temp=temp.next;
}
return count;
}
}
9.对于一个给定的链表,返回环的入口节点,如果没有环,返回null
//对于一个给定的链表,返回环的入口节点,如果没有环,返回null
//方法一:使用Map集合判断
public ListNode detectCycle(ListNode head) {
Map<ListNode,Integer> map=new HashMap<>();
ListNode temp=head;
while(temp!=null){
//map集合中已经包含当前结点,说明当前节点是环的入口
if(map.containsKey(temp)){
return temp;
}else{
map.put(temp, 1);
temp=temp.next;
}
}
return null;
}
//方法二:使用快慢指针
public ListNode detectCycle(ListNode head) {
if(head==null || head.next==null){
return null;
}
//定义快慢指针,从相同位置开始
ListNode slow=head;
ListNode fast=head;
while(true){
if(fast==null || fast.next==null){
return null;
}
fast=fast.next.next;
slow=slow.next;
if(fast==slow){
break;
}
}
//此时快指针和慢指针第一次相遇,将其中一个指针恢复到head位置,并调整步幅,直到第二次相遇的位置
//第二次相遇的位置即环的入口位置
fast=head;
while(fast!=slow){
fast=fast.next;
slow=slow.next;
}
return fast;
}
10.假设链表中每一个节点的值都在 0 - 9 之间,那么链表整体就可以代表一个整数。
给定两个这种链表,请生成代表两个整数相加值的结果链表。
例如:链表 1 为 9->3->7,链表 2 为 6->3,最后生成新的结果链表为 1->0->0->0。
package com.csu.marden;
import java.util.ArrayList;
import java.util.List;
public class Demo11 {
public static void main(String[] args) {
ListNode head1=new ListNode(1);
ListNode node2=new ListNode(2);
ListNode node3=new ListNode(3);
ListNode node5=new ListNode(4);
head1.next=node2;
node2.next=node3;
node3.next=node5;
ListNode head2=new ListNode(3);
ListNode node4=new ListNode(4);
head2.next=node4;
System.out.println("链表1:");
show(head1);
System.out.println("链表2:");
show(head2);
System.out.println("求和后链表:");
show(addInList(head1, head2));
}
public static void show(ListNode head){
ListNode temp=head;
while(temp!=null){
System.out.println(temp.value);
temp=temp.next;
}
}
//假设链表中每一个节点的值都在 0 - 9 之间,那么链表整体就可以代表一个整数。
//给定两个这种链表,请生成代表两个整数相加值的结果链表。
//例如:链表 1 为 9->3->7,链表 2 为 6->3,最后生成新的结果链表为 1->0->0->0。
public static ListNode addInList (ListNode head1, ListNode head2) {
//获取第一个链表的值
List<Integer> list1=new ArrayList<>();
ListNode temp1=head1;
while(temp1!=null){
list1.add(temp1.value);
temp1=temp1.next;
}
int num1=0;
for(int i=list1.size()-1;i>=0;i--){
num1=(int) (num1+list1.get(i)*Math.pow(10, list1.size()-i-1));
}
//获取第二个链表的值
List<Integer> list2=new ArrayList<>();
ListNode temp2=head2;
while(temp2!=null){
list2.add(temp2.value);
temp2=temp2.next;
}
int num2=0;
for(int i=list2.size()-1;i>=0;i--){
num2=(int) (num2+list2.get(i)*Math.pow(10, list2.size()-i-1));
}
//将两个链表的值相加,并重新创建新的链表
int result=num1+num2;
int length=(""+result).length();
int [] arr=new int [length];
for(int i=arr.length-1;i>=0;i--){
arr[i]=result%10;
result=result/10;
}
ListNode newhead=new ListNode(arr[0]);
ListNode last=newhead;
int i=1;
while(i<arr.length){
ListNode temp=new ListNode(arr[i]);
last.next=temp;
last=last.next;
i++;
}
return newhead;
}
}
11.给定一个二叉树,返回该二叉树层序遍历的结果,(从左到右,一层一层地遍历)
package com.csu.marden;
import java.util.ArrayList;
import java.util.LinkedList;
public class Demo13 {
public static void main(String[] args) {
TreeNode root=new TreeNode(3);
TreeNode node2=new TreeNode(9);
TreeNode node3=new TreeNode(20);
TreeNode node4=new TreeNode(15);
TreeNode node5=new TreeNode(17);
root.left=node2;
root.right=node3;
node3.left=node4;
node3.right=node5;
show(levelOrder1(root));
}
public static void show(ArrayList<ArrayList<Integer>> list){
for(int i=0;i<list.size();i++){
for(int j=0;j<list.get(i).size();j++){
System.out.print(list.get(i).get(j)+" ");
}
System.out.println();
}
}
public static ArrayList<ArrayList<Integer>> levelOrder1(TreeNode root) {
if(root==null){
return null;
}
ArrayList<ArrayList<Integer>> list=new ArrayList<>();
LinkedList<TreeNode> queue=new LinkedList<>();
queue.addLast(root);
while(queue.size()>0){ //队列长度动态变化
int length=queue.size(); //length长度固定,即当前层次的节点数目
ArrayList<Integer> templist=new ArrayList<>();
for(int i=0;i<length;i++){
TreeNode temp=queue.removeFirst();
templist.add(temp.value);
if(temp.left!=null){
queue.addLast(temp.left);
}
if(temp.right!=null){
queue.addLast(temp.right);
}
}
list.add(templist);
}
return list;
}
}
12.输入两个链表,找出它们的第一个公共结点。(注意因为传入数据是链表,所以错误测试数据的提示是用其他方式显示的,保证传入数据是正确的)
package com.csu.marden;
import java.util.HashMap;
import java.util.Map;
public class Demo14 {
public static void main(String[] args) {
ListNode pHead1=new ListNode(1);
ListNode pHead2=new ListNode(11);
ListNode node1=new ListNode(2);
ListNode node2=new ListNode(3);
ListNode node3=new ListNode(4);
ListNode node4=new ListNode(6);
ListNode node5=new ListNode(7);
ListNode node6=new ListNode(8);
pHead1.next=node1;
node1.next=node2;
node2.next=node3;
node3.next=node4;
pHead2.next=node5;
node5.next=node6;
node6.next=node3;
System.out.println(FindFirstCommonNode(pHead1, pHead2).value);
}
//输入两个链表,找出它们的第一个公共结点。(注意因为传入数据是链表,
//所以错误测试数据的提示是用其他方式显示的,保证传入数据是正确的)
public static ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
if(pHead1==null || pHead2==null){
return null;
}
Map<ListNode,Integer> map=new HashMap<>();
ListNode temp=pHead1;
while(temp!=null){
map.put(temp, 1);
temp=temp.next;
}
temp=pHead2;
while(temp!=null){
if(map.containsKey(temp)){
return temp;
}else{
temp=temp.next;
}
}
return null;
}
}
13.一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。
package com.csu.marden;
import sun.util.calendar.JulianCalendar;
public class Demo15 {
public static void main(String[] args) {
System.out.println(JumpFloor(5));
}
public static int JumpFloor(int target) {
//动态规划,dp[i]表示调到第i个台阶有多少种方法
int [] dp=new int [target+1];
//初始化
dp[1]=1;
dp[0]=1;
for(int i=2;i<dp.length;i++){
dp[i]=dp[i-1]+dp[i-2];
}
return dp[target];
}
}
14.用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。
package com.csu.marden;
import java.util.Stack;
public class Demo16 {
public static void main(String[] args) {
}
//用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。
static Stack<Integer> stack1 = new Stack<Integer>();
static Stack<Integer> stack2 = new Stack<Integer>();
public static void push(int node) {
stack1.push(node);
}
public static int pop() {
//先将stack1中的所有元素出栈,并以此入栈stack2
while(stack1.size()>0){
stack2.push(stack1.pop());
}
int temp=stack2.pop();
while(stack2.size()>0){
stack1.push(stack2.pop());
}
return temp;
}
}
15.实现 int sqrt(int x) 函数。计算并返回 x 的平方根,其中 x 是非负整数。
由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。
package com.csu.marden;
public class Demo17 {
public static void main(String[] args) {
System.out.println(sqrt(1034));
}
//采用二分法计算
public static int sqrt (int x) {
if(x==0 || x==1){
return x;
}
int start=0;
int end=x;
while(start<=end){
int mid=(start+end)/2;
if(mid*mid==x){
return mid;
}
else if(mid*mid<x){
if((mid+1)*(mid+1)>x){
return mid;
}else{
start=mid+1;
}
}else{
end=mid-1;
}
}
return 0;
}
}
16.给出一个仅包含字符'(',')','{','}','['和']',的字符串,判断给出的字符串是否是合法的括号序列.
括号必须以正确的顺序关闭,"()"和"()[]{}"都是合法的括号序列,但"(]"和"([)]"不合法。
package com.csu.marden;
import java.util.Stack;
public class Demo18 {
public static void main(String[] args) {
System.out.println(isValid("["));
}
/*
* 给出一个仅包含字符'(',')','{','}','['和']',的字符串,判断给出的字符串是否是合法的括号序列
括号必须以正确的顺序关闭,"()"和"()[]{}"都是合法的括号序列,但"(]"和"([)]"不合法。
*/
//通过栈,判断括号是否匹配
public static boolean isValid (String s) {
Stack<Character> stack1=new Stack<>();
Stack<Character> stack2=new Stack<>();
//首先判断括号序列的长度是否为偶数
if(s.length()%2==0){
//1.将所有符号压入stack1
for(int i=0;i<s.length();i++){
stack1.push(s.charAt(i));
}
//2.将stack1中的元素出栈
while(!stack1.isEmpty()){
if(stack1.peek()=='}' || stack1.peek()==']' || stack1.peek()==')'){
stack2.push(stack1.pop());
}
else if(stack1.peek()=='{'){
if(stack2.isEmpty()){
return false;
}else{
if(stack2.peek()=='}'){
stack2.pop();
stack1.pop();
}else{
stack2.push(stack1.pop());
}
}
}
else if(stack1.peek()=='['){
if(stack2.isEmpty()){
return false;
}else{
if(stack2.peek()==']'){
stack2.pop();
stack1.pop();
}else{
stack2.push(stack1.pop());
}
}
}
else if(stack1.peek()=='('){
if(stack2.isEmpty()){
return false;
}else{
if(stack2.peek()==')'){
stack2.pop();
stack1.pop();
}else{
stack2.push(stack1.pop());
}
}
}
}
if(stack2.isEmpty()){
return true;
}else{
return false;
}
}else{
return false;
}
}
}
17.输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
TreeNode root=new TreeNode(pre[0]);
if(pre.length==1){
root.left=null;
root.right=null;
return root;
}
//得到中序中根的位置
int temp=pre[0];
int index;
for(index=0;index<in.length;index++){
if(in[index]==temp){
break;
}
}
//创建左子树
if(index>0){
int [] new_pre=new int [index];
int [] new_in=new int [index];
for(int i=0;i<new_pre.length;i++){
new_pre[i]=pre[i+1];
}
for(int i=0;i<new_in.length;i++){
new_in[i]=in[i];
}
root.left=reConstructBinaryTree(new_pre, new_in);
}else{
root.left=null;
}
//创建右子树
if(index<in.length-1){
int [] new_pre=new int [pre.length-index-1];
int [] new_in=new int [pre.length-index-1];
for(int i=0;i<new_pre.length;i++){
new_pre[i]=pre[1+index+i];
}
for(int i=0;i<new_in.length;i++){
new_in[i]=in[index+1+i];
}
root.right=reConstructBinaryTree(new_pre, new_in);
}else{
root.right=null;
}
return root;
}
18.给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
package com.csu.marden;
import java.util.HashSet;
import java.util.Set;
public class Demo3 {
public static void main(String[] args) {
int [] arr={2,3,4,5};
System.out.println(maxLength(arr));
}
//暴力枚举
public static int maxLength (int[] arr) {
int maxLength=0;
for(int i=0;i<arr.length;i++){
for(int j=i+1;j<arr.length;j++){
if(judge(arr, i, j)){
maxLength=Math.max(maxLength, j-i+1);
}
}
}
return maxLength;
}
//判断是否为无重复子串
public static boolean judge(int [] arr,int start,int end){
Set<Integer> set =new HashSet<>();
for(int i=start;i<=end;i++){
if(set.contains(arr[i])){
return false;
}else{
set.add(arr[i]);
}
}
return true;
}
}
package com.csu.marden;
import java.util.HashSet;
import java.util.Set;
public class Demo4 {
public static void main(String[] args) {
String str="pwwkew";
System.out.println(maxLength(str));
}
//使用滑动窗口技术
//判断重复使用数据结构set或者map
public static int maxLength (String str) {
if(str==null || str.length()==0){
return 0;
}
Set<Character> set=new HashSet<>();
int start=0;
int end=0;
int maxLength=0;
int length=str.length();
while(start<length){
while(end<length && !set.contains(str.charAt(end))){
set.add(str.charAt(end));
end++;
}
maxLength=Math.max(maxLength, end-start);
if(end==length){
break;
}else{
set.remove(str.charAt(start));
start++;
}
}
return maxLength;
}
}
19.给定一个二叉树和一个值sum,判断是否有从根节点到叶子节点的节点值之和等于sum 的路径
public boolean hasPathSum(TreeNode root, int sum) {
if (root == null) {
return false;
}
if (root.left == null && root.right == null) {
return sum == root.val;
}
return hasPathSum(root.left, sum - root.val) || hasPathSum(root.right, sum - root.val);
}
20.给定一个二叉树,返回该二叉树的之字形层序遍历,(第一层从左向右,下一层从右向左,一直这样交替)
该二叉树之字形层序遍历的结果是
[
[3],
[20,9],
[15,7]
]
package com.csu.marden;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
public class Demo5 {
public static void main(String[] args) {
TreeNode root=new TreeNode(3);
TreeNode node1=new TreeNode(9);
TreeNode node2=new TreeNode(20);
TreeNode node3=new TreeNode(15);
TreeNode node4=new TreeNode(7);
root.left=node1;
root.right=node2;
node1.left=node3;
node1.right=node4;
show(zigzagLevelOrder(root) );
}
public static void show(ArrayList<ArrayList<Integer>> list){
for(int i=0;i<list.size();i++){
for(int j=0;j<list.get(i).size();j++){
System.out.print(list.get(i).get(j)+" ");
}
System.out.println();
}
}
public static ArrayList<ArrayList<Integer>> zigzagLevelOrder (TreeNode root) {
if(root==null){
return null;
}
ArrayList<ArrayList<Integer>> result=new ArrayList<ArrayList<Integer>>();
LinkedList<TreeNode> queue=new LinkedList<>();
queue.addLast(root); //将根节点入队
boolean flag=false; //判断是否反转(交替反转)
while(!queue.isEmpty()){
int length=queue.size();
ArrayList<Integer> list=new ArrayList<>();
for(int i=0;i<length;i++){
TreeNode temp=queue.pop();
list.add(temp.value);
if(temp.left!=null){
queue.add(temp.left);
}
if(temp.right!=null){
queue.add(temp.right);
}
}
if(flag==false){
result.add(list);
flag=!flag;
}else{
Collections.reverse(list);
result.add(list);
flag=!flag;
}
}
return result;
}
}