剑指offer(21-30)

21.输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)
    思路:借用一个辅助的栈,遍历压栈顺序,先讲第一个放入栈中,这里是1,然后判断栈顶元素是不是出栈顺序的第一个元素,这里是4,很显然1≠4,所以我们继续压栈,直到相等以后开始出栈,出栈一个元素,则将出栈顺序向后移动一位,直到不相等,这样循环等压栈顺序遍历完成,如果辅助栈还不为空,说明弹出序列不是该栈的弹出顺序。

举例:

入栈1,2,3,4,5

出栈4,5,3,2,1

首先1入辅助栈,此时栈顶1≠4,继续入栈2

此时栈顶2≠4,继续入栈3

此时栈顶3≠4,继续入栈4

此时栈顶4=4,出栈4,弹出序列向后一位,此时为5,,辅助栈里面是1,2,3

此时栈顶3≠5,继续入栈5

此时栈顶5=5,出栈5,弹出序列向后一位,此时为3,,辅助栈里面是1,2,3

….

依次执行,最后辅助栈为空。如果不为空说明弹出序列不是该栈的弹出顺序。
代码:
import java.util.ArrayList;
import java.util.Stack;

public class Solution {
    public boolean IsPopOrder(int [] pushA,int [] popA) {
      
       if(pushA.length==0||popA.length==0)
           return false;
        //辅助栈
        Stack<Integer> s=new Stack<Integer>();
        //用于标识弹出序列的位置
        int popIndex=0;
        
        for(int i=0;i<pushA.length;i++){
            s.push(pushA[i]);
            
            while(!s.empty()&&s.peek()==popA[popIndex]){
                s.pop();
                popIndex++;
            }
            
        }
        
        return s.empty();
    } 
}

22. 从上往下打印出二叉树的每个节点,同层节点从左至右打印。 
    思路:思路还是很清晰的,使用两个队列一个存放节点,一个存放值。先将根节点加入到队列中,然后遍历队列中的元素,遍历过程中,访问该元素的左右节点,再将左右子节点加入到队列中来
代码:
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 {
    public ArrayList<Integer> PrintFromTopToBottom(TreeNode root) {
        
        ArrayList<TreeNode> listNode=new ArrayList<TreeNode>();
        ArrayList<Integer> listVal=new ArrayList<Integer>();
        
        if(root==null)
            return listVal;
        
        listNode.add(root);
        listVal.add(root.val);
        
       for(int i=0;i<listNode.size();i++){
           TreeNode node=listNode.get(i);
        
        	if(node.left!=null){
                listNode.add(node.left);
                listVal.add(node.left.val);
            }
        
        	if(node.right!=null){
                listNode.add(node.right);
                listVal.add(node.right.val);
            }
       }
        return listVal;	
    }
    
    	
}

23.输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。
    思路:对于后序遍历来说,序列数组的最后一个元素一定是根节点,
               则根据这个元素,将前面的数组分为左、右两个部分,左侧部分都小,右侧部分都大,
               如果右侧部分有比该根节点小的元素,那么就不是后序遍历,如此递归进行
代码:
public class Solution {
    public boolean VerifySquenceOfBST(int [] sequence) {
        
       if(sequence==null||sequence.length==0)
           return false;
        
       boolean flag=this.isBST(sequence,0,sequence.length-1);
        
        return flag;
    }
    
    public boolean isBST(int[] arr,int start, int end){
        if(start>=end)
            return true;
        
         // 当前数组(从start到end部分)的根节点
        int curElement=arr[end];
        int splitIndex;
         // 找到比curElement大和比curElement小的分界点,分成左侧、右侧两组数据
        for(splitIndex=start;splitIndex<end&&arr[splitIndex]<curElement;splitIndex++);
        
        
        // 只需要看右侧即可,因为前面的for循环,已经确保左侧部分全部都小于curElement
        for(int i=splitIndex;i<end;i++){
            if(arr[i]<curElement)
            return false;
        }
        
        return isBST(arr,start,splitIndex-1)&&isBST(arr,splitIndex,end-1);
    }
}

24.输入一颗二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。
    思路:经典的递归策略
代码:
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 {
    public ArrayList<ArrayList<Integer>> FindPath(TreeNode root,int target) {
        
        ArrayList<ArrayList<Integer>> paths=new ArrayList<ArrayList<Integer>>();
        
    	if(root==null)
            return paths;
        
        find(paths,new ArrayList<Integer>(),root,target);
        
        return paths;
        
    }
    
    public void find(ArrayList<ArrayList<Integer>> paths,ArrayList<Integer> path,TreeNode root,int target){
        
        path.add(root.val);
        
        if(root.left==null&&root.right==null){
            
            if(target==root.val)
                paths.add(path);
            
              return;
        }
        
      
        
        ArrayList<Integer> path2=new ArrayList<Integer>();
        path2.addAll(path);
        
        if(root.left!=null)
            find(paths,path,root.left,target-root.val);
        if(root.right!=null)
            find(paths,path2,root.right,target-root.val);
    }
      
}

25.输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)
    思路:

代码:
/*
public class RandomListNode {
    int label;
    RandomListNode next = null;
    RandomListNode random = null;

    RandomListNode(int label) {
        this.label = label;
    }
}
*/
public class Solution {
    public RandomListNode Clone(RandomListNode pHead){

        if(pHead==null)
            return null;

        RandomListNode node=new RandomListNode(pHead.label);

        node.next=pHead.next;
        node.random=pHead.random;
        node.next=Clone(pHead.next);

        return node;
    }
}

26.输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创 建任何新的结点,只能调整树中结点指针的指向。
    思路: 采用中序遍历 , 修改中序遍历,在其中加入一个前驱结点 
遍历左子树
当前结点指向左指针指向前驱结点 , 前驱结点右指针指向当前结点 
前驱 = 当前
遍历右子树
代码:
/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

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

    }

}
*/
public class Solution {
    
    TreeNode head=null;
    TreeNode realhead=null;
    
    public TreeNode Convert(TreeNode pRootOfTree) {
    	    Convertsub(pRootOfTree);
        	return realhead;
    }
    
    public void Convertsub(TreeNode pRootOfTree){
        
        if(pRootOfTree==null)
            return;
        Convertsub(pRootOfTree.left);
        if(head==null){            
            head=realhead=pRootOfTree;
        }else{
            pRootOfTree.left=head;
            head.right=pRootOfTree;
            head=pRootOfTree;
        }
        Convertsub(pRootOfTree.right);
    }
    
    
}

27. 输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。 结果请按字母顺序输出。 
输入描述:
输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。
    思路:

28:数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
    思路:使用HashMap
代码:
import java.util.HashMap;

public class Solution {
    public int MoreThanHalfNum_Solution(int [] array) {
        
        if(array.length==0||array==null)
            return 0;
        
        HashMap<Integer,Integer> map=new HashMap<Integer,Integer>();
        for(int i=0;i<array.length;i++){
            Integer tmp=map.get(array[i]);
            if(tmp==null){
                map.put(array[i],1);
                tmp=1;
            }else{
                map.put(array[i],tmp+1);                
            }
            if(tmp+1>array.length/2)
                return array[i];
        }
        
        return 0;
    }
}

29.输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。
    思路:第一种方法类似冒泡排序,第二种直接使用数组排序的API
代码:
第一种:
import java.util.ArrayList;

public class Solution {
    public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
        
        ArrayList<Integer> al=new ArrayList<Integer>();
        if(k>input.length)
            return al;
        
        for(int i=0;i<k;i++){
            for(int j=0;j<input.length-1-i;j++){
            if(input[j]<input[j+1]){
                int tmp=input[j+1];
                input[j+1]=input[j];
                input[j]=tmp;
            }
        }
            al.add(input[input.length-1-i]);
      }
       
        
        return al;
    }
}


第二种:

import java.util.ArrayList;
import java.util.Arrays;

public class Solution {
    public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
        
        ArrayList<Integer> al=new ArrayList<Integer>();
   
        if(k>input.length)
            return al;
        
        Arrays.sort(input);
        
        for(int i=0;i<k;i++){
            al.add(input[i]);
        }
        
        return al;
    }
}

30.HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。你会不会被他忽悠住?
    思路:动态规划
代码:
public class Solution {
    public int FindGreatestSumOfSubArray(int[] array) {
        
        if(array.length==0)
            return 0;
        
        int sum=array[0];
        int tmp=array[0];
        for(int i=1;i<array.length;i++){
            
            tmp=tmp<0?array[i]:tmp+array[i];
            sum=Math.max(sum,tmp);
        }
        
        return sum;
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值