11天刷完《剑指Offer》/ Day3:第21~30题

T21 栈的压入弹出序列

  • 题目描述

输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)

  • 思路:

新建一个栈,将数组A压入栈中,当栈顶元素等于数组B时,就将其出栈,当循环结束时,判断栈是否为空,若为空则返回true.

import java.util.ArrayList;
import java.util.Stack;//开始不知道,没引入,stack新建报错!!!!

public class Solution {
    public boolean IsPopOrder(int [] pushA,int [] popA) {
       if(pushA==null||popA==null||pushA.length!=popA.length)
          return false;
        Stack<Integer> st = new Stack<Integer>();
        int j=0;
       for(int a: pushA){
           st.push(a);
           while(j<popA.length && st.peek()==popA[j]){
               stack.pop();
               j++;
           }
       }
       return st.isEmpty();
    }
    }
}

注意:

引入 import java.util.Stack;!!!!!!!

Java新建栈

栈是Vector的一个子类,它实现了一个标准的后进先出的栈,栈本身最重要的就是 push 和 pop.
堆栈只定义了默认构造函数,用来创建一个空栈。堆栈除了包括由Vector定义的所有方法,也定义了自己的一些方法
Stack()
除了由Vector定义的所有方法,自己也定义了一些方法:

序号	方法描述
1	boolean empty() 
测试堆栈是否为空。
2	Object peek( )
查看堆栈顶部的对象,但不从堆栈中移除它。
3	Object pop( )
移除堆栈顶部的对象,并作为此函数的值返回该对象。
4	Object push(Object element)
把项压入堆栈顶部。
5	int search(Object element)
返回对象在堆栈中的位置,以 1 为基数。

用栈Stack 创建对象(类型不同)
	Stack<Integer> stack = new Stack<>();
	Stack<Character> stack = new Stack<>();
————————————————
版权声明:本文为CSDN博主「宝宝辉AD」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_42124842/article/details/91420306

T22从上往下打印二叉树

  • 题目描述

从上往下打印出二叉树的每个节点,同层节点从左至右打印。

  • 解题思路

每一次打印一个节点的时候,如果该节点有子节点,则把该节点的子节点放到一个队列的尾部。接下来到对队列的头部取出最早进入队列的节点放到ArrayList 中,重复前面的操作,直至队列中所有的节点都存到ArrayList中

import java.util.ArrayList;
import java.util.Deque;
import java.util.LinkedList;
/**
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) {
        Deque<TreeNode> que = new LinkedList<>();
        ArrayList<Integer> res = new ArrayList<>();
 
        if(root == null)
            return res;
 
        que.add(root);
 
        while(!que.isEmpty()){
            TreeNode node = que.getFirst();
            que.pollFirst();
            res.add(node.val);
  			//先左后右按顺序压入子结点
            if(node.left != null)
                que.addLast(node.left);
            if(node.right != null)
                que.addLast(node.right);
        }
        return res;
    }
}

注意:

队列Queue:像栈一样,队列也是一种线性表,特性是先进先出,插入在一端,删除在另一端。就像排队一样,刚来的人入队(push)要排在队尾(rear),每次出队(pop)的都是队首(front)的人。

在这里插入代码片

LinkedList

在Java中Queue是和List、Map同等级别的接口,LinkedList类实现了Queue接口,因此我们可以把LinkedList当成Queue来用。该接口中的主要函数有:

1。(常用)容量不够或队列为空时不会抛异常:offer(添加队尾元素)、peek(访问队头元素)、poll(访问队头元素并移除)
2。容量不够或队列为空时抛异常:add(添加队尾元素)、element(访问队头元素)、remove(访问队头元素并移除)

T23. 二叉搜索树的后序遍历序列!

  • 题目描述

输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。

  • 解题思路:
public class Solution {
    public boolean VerifySquenceOfBST(int [] sequence) {
        if(sequence.length==0) return false;
        return IsTreeBST(sequence,0,sequence.length-1);
    }
    public boolean IsTreeBST(int[] sequence,int start,int end){
        if(end <= start) return true;
        int i=start;
        for(;i<end;i++){
            if(sequence[i]>sequence[end]) break;
        }
        for(int j=i;j<end;j++){
            if(sequence[j]<sequence[end]) return false;
        }
        return IsTreeBST(sequence,start,i-1) && IsTreeBST(sequence,i,end-1);
        
    }
}

注意:后序遍历(BST)

T24. 二叉树中和为某一值的路径!

  • 题目描述

输入一颗二叉树的根结点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。(注意: 在返回值的list中,数组长度大的数组靠前)

  • 解题思路

1. 递归法:

深度优先搜索(DFS),通过减法的思想不断用target减去当前结点值,能减为0则是一条路径。
条件----路径要求最后到达叶子结点。
迭代过程中需把当前值在path中移除以保证路径正确,相当于回退到上一步的路径。

import java.util.ArrayList;
/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    private ArrayList<ArrayList<Integer>> result=new ArrayList<ArrayList<Integer>>();
    private ArrayList<Integer> list=new ArrayList<>();
    public ArrayList<ArrayList<Integer>> FindPath(TreeNode root,int target) {
        if(root==null) return result;
        list.add(root.val);
        target -= root.val;
        if(target==0 && root.left==null && root.right==null){
            result.add(new ArrayList<Integer>(list)); //因为result.add(list)是吧list这个对象的引用地址添加到result了,result中的元素就会共用list,而list是我们用来存放当前路径的地方,因此我们需要复制一份之后加入result数组中
        }
        FindPath(root.left,target);
        FindPath(root.right,target);
        //递归时result重复调用
        list.remove(list.size()-1);//子节点退回一步
        return result;
    }
}

2. 非递归

T25. 复杂链表的复制!

题目描述
输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)
解题思路:
不用开辟新的Map,但是其实需要多次遍历。
链接:https://www.nowcoder.com/questionTerminal/f836b2c43afc4b35ad6adc41ec941dba?f=discussion
来源:牛客网

/*
*解题思路:
*1、遍历链表,复制每个结点,如复制结点A得到A1,将结点A1插到结点A后面;
*2、重新遍历链表,复制老结点的随机指针给新结点,如A1.random = A.random.next;
*3、拆分链表,将链表拆分为原链表和复制后的链表
*/

public class Solution {

public RandomListNode Clone(RandomListNode pHead) {
    if(pHead == null) {
        return null;
    }
    
    RandomListNode currentNode = pHead;
    //1、复制每个结点,如复制结点A得到A1,将结点A1插到结点A后面;
    while(currentNode != null){
        RandomListNode cloneNode = new RandomListNode(currentNode.label);
        RandomListNode nextNode = currentNode.next;
        currentNode.next = cloneNode;
        cloneNode.next = nextNode;
        currentNode = nextNode;
    }

    currentNode = pHead;
    //2、重新遍历链表,复制老结点的随机指针给新结点,如A1.random = A.random.next;
    while(currentNode != null) {
        currentNode.next.random = currentNode.random==null?null:currentNode.random.next;
        currentNode = currentNode.next.next;
    }

    //3、拆分链表,将链表拆分为原链表和复制后的链表
    currentNode = pHead;
    RandomListNode pCloneHead = pHead.next;
    while(currentNode != null) {
        RandomListNode cloneNode = currentNode.next;
        currentNode.next = cloneNode.next;
        cloneNode.next = cloneNode.next==null?null:cloneNode.next.next;
        currentNode = currentNode.next;
    }

    return pCloneHead;
}

}

T26. 二叉搜索树与双向链表!

  • 题目描述

输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。

  • 解题思路:

T27字符串的排列!

  • 题目描述

输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。

  • 解题思路:
/**
     * 1、递归算法
     *
     * 解析:http://www.cnblogs.com/cxjchen/p/3932949.html  (感谢该文作者!)
     *
     * 对于无重复值的情况
     *
     * 固定第一个字符,递归取得首位后面的各种字符串组合;
     * 再把第一个字符与后面每一个字符交换,并同样递归获得首位后面的字符串组合; *递归的出口,就是只剩一个字符的时候,递归的循环过程,就是从每个子串的第二个字符开始依次与第一个字符交换,然后继续处理子串。
     *
     * 假如有重复值呢?
     * *由于全排列就是从第一个数字起,每个数分别与它后面的数字交换,我们先尝试加个这样的判断——如果一个数与后面的数字相同那么这两个数就不交换了。
     * 例如abb,第一个数与后面两个数交换得bab,bba。然后abb中第二个数和第三个数相同,就不用交换了。
     * 但是对bab,第二个数和第三个数不 同,则需要交换,得到bba。
     * 由于这里的bba和开始第一个数与第三个数交换的结果相同了,因此这个方法不行。
     *
     * 换种思维,对abb,第一个数a与第二个数b交换得到bab,然后考虑第一个数与第三个数交换,此时由于第三个数等于第二个数,
     * 所以第一个数就不再用与第三个数交换了。再考虑bab,它的第二个数与第三个数交换可以解决bba。此时全排列生成完毕!
     *
     *
     * @param str
     * @return
     */
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;

public class Solution {
    public ArrayList<String> Permutation(String str) {
        ArrayList<String> list = new ArrayList<String>();
        if(str!=null && str.length()>0){
            PermutationHelper(str.toCharArray(),0,list);
            Collections.sort(list);
        }
        return list;
    }
     private void PermutationHelper(char[] chars,int i,ArrayList<String> list){
        if(i == chars.length-1){
            list.add(String.valueOf(chars));
        }else{
            HashSet<Character> charSet = new HashSet<Character>();
            for(int j=i;j<chars.length;++j){
                if(j==i || !charSet.contains(chars[j])){
                    charSet.add(chars[j]);
                    swap(chars,i,j);
                    PermutationHelper(chars,i+1,list);
                    swap(chars,j,i);
                }
            }
        }
    }
 
    private void swap(char[] cs,int i,int j){
        char temp = cs[i];
        cs[i] = cs[j];
        cs[j] = temp;
    }
 
}

//String的用法:
//java中String是只读的,没有办法进行变换,因此需要使用StringBuilder。
String.length() //获取字符串的长度
String.charAt(i) //获取第i个字符的内容
String.subString(start)   //获取[start,)的字符串
String.subString(start,end) //获取[start,end)中的字符串
char[] c = iniString.toCharArray() //将字符串转为char数组来进行改变字符内容
String.equal() //判断两个字符串是否相等
 
//StringBuilder的用法:
除了String中支持的方法外,StringBuilder支持字符的增、删、改。
stringBuilder.append("we");  //添加we在词尾
stringBuilder.insert(0,"we");//0的位置加入后面的内容
stringBuilder.delete(0,1);  //删除[0,1)的数据
stringBuilder.deleteCharAt(0);
stringBuilder.setCharAt(0,'p'); //在某一个独特位置设置字符
char c = stringBuilder.charAt(i);//查询某个位置上的字符
System.out.println(stringBuilder);
new String(stringBuilder);//用stringBuilder来初始化String

T28 数组中出现次数超过一半的数字

  • 题目描述

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。

  • 解题思路:
public class Solution {
    public int MoreThanHalfNum_Solution(int [] array) {
        if(array==null||array.length==0) return 0;
        int k=0;//循环里return a或0,会不确定循环结束前后到底有没有
        for(int a:array){
        //每个数都作为基准和所有数对比,计数
            int num=0;
            for(int i=0;i<array.length;i++){
                if(array[i]==a) num++;
            }
            if(num>array.length/2) k=a;
        }
   return k;}
}

T29最小的K个数!

  • 题目描述

输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。

  • 解题思路

用最大堆保存这k个数,每次只和堆顶比,如果比堆顶小,删除堆顶,新数入堆。

链接:https://www.nowcoder.com/questionTerminal/6a296eb82cf844ca8539b57c23e6e9bf?f=discussion
来源:牛客网

import java.util.ArrayList;
import java.util.PriorityQueue;
import java.util.Comparator;
public class Solution {
   public ArrayList<Integer> GetLeastNumbers_Solution(int[] input, int k) {
       ArrayList<Integer> result = new ArrayList<Integer>();
       int length = input.length;
       if(k > length || k == 0){
           return result;
       }
        PriorityQueue<Integer> maxHeap = new PriorityQueue<Integer>(k, new Comparator<Integer>() {
 
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2.compareTo(o1);
            }
        });
        for (int i = 0; i < length; i++) {
            if (maxHeap.size() != k) {
                maxHeap.offer(input[i]);
            } else if (maxHeap.peek() > input[i]) {
                Integer temp = maxHeap.poll();
                temp = null;
                maxHeap.offer(input[i]);
            }
        }
        for (Integer integer : maxHeap) {
            result.add(integer);
        }
        return result;
    }
}

T30连续子数组的最大和

  • 题目描述

HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。给一个数组,返回它的最大连续子序列的和,你会不会被他忽悠住?(子向量的长度至少是1)

  • 解题思路
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
 
public class Solution {
    public int FindGreatestSumOfSubArray(int[] array) {
       List<Integer> list = new ArrayList<>();
        for(int i=0;i<array.length;i++){
            int sum = 0;
            for(int j=i;j<array.length;j++){
                sum += array[j];
                list.add(sum);
            }
        }
        if(list.size() <=0) return 0;
        Collections.sort(list);
        return list.get(list.size()-1);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值