剑指Offer刷题(二)及思路

栈的压入、弹出序列

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

import java.util.ArrayList;
import java.util.Stack;
public class Solution {
    public boolean IsPopOrder(int [] pushA,int [] popA) {
       if(pushA.length!=popA.length)return false;
       Stack<Integer> stack = new Stack<Integer>();
       int length = pushA.length;
        int popIndex = 0;
        for(int i = 0;i<length;i++)
        {
            stack.push(pushA[i]);
           
            while(!stack.empty()&&stack.peek()==popA[popIndex])
            {
                stack.pop();
                popIndex++;
            }

        }
        return stack.isEmpty();
        
    }
}

直接模拟题目叙述的入栈和出栈过程即可,
例如如栈1 2 3 4 ,到4时,检测到与出栈顺序第一个相同,就pop,下个出栈的是5,这时栈里为 1 2 3 ,5入栈,检测到与要出栈的相同,pop,依次进行下去,如果最后栈为空,就说明是栈的一个弹出序列

从上往下打印二叉树

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

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<Integer> list = new ArrayList<Integer>();
        ArrayList<TreeNode> queue = new ArrayList<TreeNode>();
         if(root==null) return list;
        queue.add(root);
        while(queue.size()!=0)
        {
            TreeNode tmp = queue.remove(0);
            if(tmp.left!=null)
            {
                queue.add(tmp.left);
            }
            if(tmp.right!=null)
            {
                queue.add(tmp.right);
            }
            list.add(tmp.val);
        }
        return list;
    }

}

用队列实现,依次加入结点,左子结点,右子结点到队列中,
依次取队列中头一个,把它的左右结点加入队列,然后把值加到list里,直到把队列取空

二叉搜索树的后序遍历序列

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

public class Solution {
    public boolean VerifySquenceOfBST(int [] sequence) {
        int length = sequence.length;
        if(length==1)return true;
        if(length==0)return false;
        return isTree(sequence,0,length-1);
        
        
    }
    public static boolean isTree(int[] subarr, int begin,int end)
    {
        int i = end-1;
        if(begin>end)return true;
        
        //从数组的最后一个元素向前遍历,最后一个元素必定是根节点,往前找直到找到比它小的
        while( i>begin && subarr[i] > subarr[end] )
        {
            i--;
        }
        //找到比根节点小的元素位置,以这个元素为基准,左边是左子树部分,右边是右子树部分
        //右边的右子树部分已经验证都比根节点大,那么开始验证左边是不是都比根节点小
        int leftend = i;
        //如果全部元素都大于最后一个根结点,就没有左边的元素,也是成立的
        if(leftend==0)return true;
        while(i>=begin)
        {
            if(subarr[i]>subarr[end])return false;
            i--;
        }
        //左边的都满足比根节点小,进行分割递归调用
        return isTree(subarr,begin,leftend) && isTree(subarr,leftend+1,end-1);
        
    }
}

如下图是一个搜索二叉树和它的后序遍历

在这里插入图片描述在这里插入图片描述
要判断一个序列是不是二叉搜索树的后序遍历,首先要明确:

  • 这个序列的最后一个元素必定是根节点
  • 根节点的左半边所有结点都比根节点小,右半边都比根节点大
  • 对每个中间结点也都有这个性质

所以,找出序列最后一个元素A,向前遍历,找到第一个比A小的元素B,说明这个元素是A的左子树结点,那么就要满足再往前遍历所有元素值都要比A小,否则就退出遍历返回false(此时已经保证了右半边都比A大,因为B是第一个比A小的)
如果这一层判断完毕,就把元素数组以B为中间分成两半,每一半再根据上面的规则进行判断,直到分割成单个元素
在这里插入图片描述

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

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

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>> List = new ArrayList<ArrayList<Integer>>();
    //子list
    private ArrayList<Integer> subList = new ArrayList<Integer>();
    public ArrayList<ArrayList<Integer>> FindPath(TreeNode root,int target) {
       if(root == null)return List;
        
        subList.add(root.val);
        //每加入一个结点的值,就把目标和数值减去这个值
        target -= root.val;
        //当前结点若为叶子结点,且subList中所有元素的和等于target
        //就把这个subList加入List
        if(target == 0 &&root.left==null&&root.right== null)
        {
            //必须要 new 一个新的list,否则后面移除元素时会造成影响
            List.add(new ArrayList<Integer>(subList));
        }
        FindPath(root.left,target);
        FindPath(root.right,target);
            //递归到底后,需要退回上一层结点,故加入的结点要去掉一个
        subList.remove(subList.size()-1);
        return List;
        
        
        
        }
    
    
}

复杂链表的复制

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

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

    RandomListNode(int label) {
        this.label = label;
    }
}
*/
import java.util.HashMap;
public class Solution {
    public RandomListNode Clone(RandomListNode pHead)
    {
        if(pHead==null)return pHead;
        //整一个HashMap,key是原来的Node结点,Value是复制后的Node结点
        HashMap<RandomListNode,RandomListNode> map = new HashMap<RandomListNode,RandomListNode>();
        RandomListNode cur = pHead ; 
        while(cur !=null)
        {
            map.put(cur,new RandomListNode(cur.label));
            cur = cur.next;
        }
        
        RandomListNode res = map.get(pHead);
        cur = pHead;
        while(cur!=null)
        {
            map.get(cur).next = map.get(cur.next);
            map.get(cur).random = map.get(cur.random);
            cur = cur.next;
        }
        return res;
    }
}

一个HashMap,key是原来的链表节点,value是新的链表节点,刚开始put进去时,value只有复制的一份节点值,没有next和random,通过get取到相应节点的复制节点,然后把原节点的next和random对象赋给复制节点的next和random引用
在这里插入图片描述
进行复制信息的操作解释:
在这里插入图片描述

二叉搜索树与双向链表

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

/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

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

    }

}
*/
public class Solution {
    public TreeNode Convert(TreeNode root) {
    	//如果节点为null,直接返回null
        if(root == null) return null;
        //如果节点为叶子节点,返回该节点
        if(root.left==null&&root.right==null)
            return root;
        //左子树递归地构造成双向链表
        TreeNode left = Convert(root.left);
        TreeNode p = left;
        //遍历到双向链表的最右边
        while(p!=null&&p.right!=null)
        {
            p=p.right;
        }
        if(left!=null)
        {
            p.right =root;
            root.left = p;
        }
        //右边也一样
        TreeNode right = Convert(root.right);
        if(right!=null)
        {
            right.left=root;
            root.right =right;
        }
        if(left!=null)return left;
        return root;
    }
    

}

在这里插入图片描述
如图一棵二叉搜索树,要转变为
在这里插入图片描述

字符串的排列

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

import java.util.*;
public class Solution {
    public ArrayList<String> Permutation(String str) {
        ArrayList<String> list = new ArrayList<String>();
       char[] charArr = str.toCharArray();
       if(str!=null){
           fun(charArr,list,0);
           Collections.sort(list);
       }
        return list;
       
       
    }
    
    public static void fun(char[] charArr,ArrayList<String> list,int i)
    {
        if(i==charArr.length-1)
        {
            String str = String.valueOf(charArr);
            if(!list.contains(str))
            {
                list.add(str);
            }
        }
        for(int j = i;j<charArr.length;j++)
        {
            swap(charArr,j,i);
            fun(charArr,list,i+1);
            swap(charArr,j,i);
        }
    }
    
    public static void swap(char[] charArr,int i,int j)
    {
        if(i!=j)
        {
            char tmp = charArr[i];
            charArr[i] = charArr[j];
            charArr[j] = tmp;
        }
    }
}

全排列,用递归做
ABC ,固定A i=0,j=0 swap

  • BC,固定B i=1,j=1 swap
    • C,添加ABC i=2,j=2 swap
  • CB,固定C i=1,j=2 swap
    • B,添加ACB i=1,j=2 swap

BAC,固定B i=0,j=1 swap

  • AC,固定A i=1,j=1 swap
    • C,添加BAC i=2,j=2 swap
  • CA,固定C i=1,j=2 swap
    • A,添加BCA i=1,j=2 swap

CBA,固定C i=0,j=2 swap

  • BA,固定B i=1,j=1 swap
    • A,添加CBA i=2,j=2 swap
  • AB,固定A i=1,j=2 swap
    • B,添加CAB i=1,j=2 swap

全排列把自己写晕了。。。
发现i j相同时,swap是不改变原来的值的,之后ij 不同,swap才在原来的基础上改变

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值