左神 数据结构算法书籍代码

目录

栈和队列

1.设计一个有getMin功能的栈

2.两个栈组成的队列

3.如何仅用递归函数和栈操作逆序一个栈

字符串问题

1.判断两个字符出是否互为变形词

2.判断两个字符串是否互为旋转字符串

3.将整数字符串转成整数值


 


栈和队列

1.设计一个有getMin功能的栈

实现一个特殊的栈,在实现栈的基本功能的基础上,再实现返回栈中最小元素的操作。

private Stack<Integer> stack=new Stack<>();
    private Stack<Integer> MinStack =new Stack<>();

    public int pop(){
        if(stack.isEmpty()) throw new RuntimeException("栈空");
        int p=stack.pop();
        if(p==this.getMin()) MinStack.pop();
        return p;
    }

    public void push(int n){
        stack.push(n);
        if(MinStack.isEmpty()||MinStack.peek()>=n){
            MinStack.push(n);
        }
    }

    public int getMin(){
        if(MinStack.isEmpty()) throw new RuntimeException("栈空");
        return MinStack.peek();
    }

2.两个栈组成的队列

一个栈用来push,一个栈用来pop。pop栈为空时,应先将push栈一个一个放到pop栈中。

//两个栈实现一个队列

    private Stack<Integer> stackPop=new Stack<>();
    private Stack<Integer> stackPush=new Stack<>();

    private void pushStack1ToStack2(){
      if(stackPop.isEmpty()){
          while(!stackPush.isEmpty()) stackPop.push(stackPush.pop());
      }
    }

    public int poll(){
        if(stackPop.isEmpty()&&stackPush.isEmpty()) throw new RuntimeException("队列为空");
        pushStack1ToStack2();
        return stackPop.pop();
    }

    public void add(int n){
      stackPush.push(n);
      pushStack1ToStack2();
    }


    public int peek(){
        if(stackPop.isEmpty()&&stackPush.isEmpty()) throw new RuntimeException("队列为空");
        pushStack1ToStack2();
        return stackPop.peek();
    }

3.如何仅用递归函数和栈操作逆序一个栈

一个栈依次压入1、2、3、4、5,那么从栈顶到栈底分别为5、4、3、2、1。将这个栈转置后,从栈顶到栈底为 1、2、3、4、5,也就是实现栈中元素的逆序,但是只能用递归函数来实现,不能用其他数据结构。

 public static void main(String[] args) {
        Stack<Integer> stack = new Stack<>();

        stack.push(1);
        stack.push(2);
        stack.push(3);
        stack.push(4);
        stack.push(5);
        new Problem3().reverseStack(stack);
        System.out.println();
    }

public int getLastElementAndRemoveFromStack(Stack<Integer> stack){
        int p = stack.pop();
        if(stack.isEmpty()){
            return p;
        }
        else {
            int last =getLastElementAndRemoveFromStack(stack);
            stack.push(p);
            return last;
        }
    }

public void reverseStack(Stack<Integer> stack){
        if(stack.isEmpty()) return;
        int p = getLastElementAndRemoveFromStack(stack);
        reverseStack(stack);
        stack.push(p);
   }

4.猫狗队列

其实本题比较简单,构建一个新的类用来承装Pet并且计数。

/*public class Pet{
    private String type;

    public Pet(String type){
        this.type=type;
    }
    public String getType(){
        return this.type;
    }
}
class Dog extends Pet{
    public Dog(){
        super("Dog");
    }
}
class Cat extends Pet{
    public Cat(){
        super("Cat");
    }
}*/

//承装 Pet
public class PetEnterQueue {
    private Pet pet;
    private long count;
    public PetEnterQueue(Pet pet,long count){
        this.pet=pet;
        this.count=count;
    }
    public Pet getPet(){
        return this.pet;
    }
    public long getCount(){
        return this.count;
    }
    public String getEnterPetType(){
        return this.pet.getType();
    }
}
public class DogCatQueue {
    private LinkedList<PetEnterQueue> DogQueue;
    private LinkedList<PetEnterQueue> CatQueue;
    private long count;
    //add  pollAll pollDog pollCat   isEmpty  isDogEmpty isCatEmpty
    public static void main(String[] args) {
        DogCatQueue queue =new DogCatQueue();
        queue.add(new Dog());
        System.out.println();
    }
    public DogCatQueue(){
        DogQueue=new LinkedList<>();
        CatQueue=new LinkedList<>();
        count=0;
    }
    public void add(Pet pet){
        if(pet.getType().equals("Dog")){
            DogQueue.add(new PetEnterQueue(pet,this.count++));
        }
        else if(pet.getType().equals("Cat")){
            CatQueue.add(new PetEnterQueue(pet,this.count++));
        }
        else throw new RuntimeException("类型错误");
    }
    public Pet PollAll(){
        if (!DogQueue.isEmpty()&&!CatQueue.isEmpty()){
            if(DogQueue.peek().getCount()>CatQueue.peek().getCount()) return DogQueue.poll().getPet();
            else return CatQueue.poll().getPet();
        }
        if(!DogQueue.isEmpty()) return DogQueue.poll().getPet();
        if(!CatQueue.isEmpty()) return CatQueue.poll().getPet();
        throw new RuntimeException("队列已空");

    }
    public Pet pollDog(){
        if(!DogQueue.isEmpty()) return DogQueue.poll().getPet();
        else throw new RuntimeException("队列已空");
    }

    public Pet pollCat(){
        if(!CatQueue.isEmpty()) return CatQueue.poll().getPet();
        else throw new RuntimeException("队列已空");
    }
    public boolean isEmpty(){
        return DogQueue.isEmpty()&&CatQueue.isEmpty();
    }
    public boolean isDogEmpty(){
        return DogQueue.isEmpty();
    }
    public boolean isCatEmpty(){
        return CatQueue.isEmpty();
    }

}

5.用一个栈实现另一个栈的排序

一个栈中元素的类型为整型,现在想将该栈从顶到底按从大到小的顺序排序,只许申请一个栈。除此之外,可以申请新的变量,但不能申请额外的数据结构。如何完成排序?

开始一直想着每次去递归取出栈中的最大元素,放入另一个栈中,然后再回弹到本栈中,这样实在太复杂。由于有额外的栈,问题的解答其实很简单。

将要排序的栈记为stack,申请的辅助栈记为help。在stack上执行pop操作,弹出的元素记为cur。

● 如果cur小于或等于help的栈顶元素,则将cur直接压入help;

● 如果cur大于help的栈顶元素,则将help的元素逐一弹出,逐一压入stack,直到cur小于或等于help的栈顶元素,再将cur压入help。一直执行以上操作,直到stack中的全部元素都压入到help。最后将help中的所有元素逐一压入stack,即完成排序。

public void solution(Stack<Integer> stack){
        Stack<Integer> helpStack = new Stack<>();
        while (!stack.isEmpty()){
            int p =stack.pop();
            while (!helpStack.isEmpty()&&helpStack.peek()<p){
                stack.push(helpStack.pop());
            }
            helpStack.push(p);
        }
        while (!helpStack.isEmpty()){
            stack.push(helpStack.pop());
        }
    }

6.生成窗口最大值数组

有一个整型数组arr和一个大小为w的窗口从数组的最左边滑到最右边,窗口每次向右边滑一个位置。

这个题好像剑指offer做过??然而我又忘了,实在是太笨了....

public int[] solution(int[] arr,int n){
        if(arr==null||n<1||arr.length<n) return null;
        LinkedList<Integer> queue =new LinkedList<>();
        int[] rs =new int[arr.length-n+1];
        int j=0;
        for(int i=0;i<arr.length;i++){
            while (!queue.isEmpty()&&arr[queue.peekLast()]<arr[i]){
                queue.pollLast();
            }
            queue.addLast(i);
            if(queue.peekFirst()==i-n){
                queue.pollFirst();
            }
            if(i>=n-1){
                rs[j]=arr[queue.peekFirst()];
                j++;
            }


        }
        return rs;

    }

字符串问题

1.判断两个字符出是否互为变形词

刚上来看题,只能想到最笨的代码,遍历两个字符串并且在Set中保存已经比较过的索引,代码如下。

public boolean solution(String str1,String str2){
        if(str1.length()!=str2.length()) return false;
        Set<Integer> set =new HashSet<>();
        for(int i=0;i<str1.length();i++){
            for(int j=0;j<str1.length();j++){
                if(set.contains(j)) continue;
                if(str1.charAt(i)==str2.charAt(j)) set.add(j);
            }
        }
        return set.size()==str1.length();
//        if(set.size()<str1.length()) return false;
//        else return true;

    }

左神书上提供的最优解,使用了一个数组做字符和出现次数的映射,思路非常巧妙。(突然想起似乎很久以前在哪见过这个题....233)。这里假定的是字符的编码在0~255内,如果字符类型非常多,可以考虑采用Map结构替代数组。

public boolean solution(String s1,String s2){
        if(s1.length()!=s2.length()) return false;
        int[] map =new int[256];
        for(int i=0;i<s1.length();i++){
            map[s1.charAt(i)]++;
        }
        for(int j=0;j<s2.length();j++){
            map[s2.charAt(j)]--;
            if(map[s2.charAt(j)]<0) return false;
        }
        return true;
    }

2.判断两个字符串是否互为旋转字符串

这题的解题方法也是很巧妙的,比如说对于字符串a="abcd"和字符串b="dabc",只需要构建另一个字符串s=b+b="dabcdabc",然后,在s中寻找是否存在等于a的字串即可。

因为对于s=b+b这个字符串来说,所有长度为b.length的字符串,都是b的旋转字符串,这就是规律所在。因此,s包含了所有b的旋转字符串,那么a如果是b的旋转字符串,必定可以找到它。

public boolean solution(String s1,String s2){
        if(s1==null||s2==null||s1.length()==0||s2.length()==0) return false;
        String s =s2+s2;
        return getIndexOf(s,s1);// getIndexOf函数通过KMP算法实现
    }

这里提到了KMP算法,这个算法解决的问题就是只使用O(m+n)的复杂度找到一个字符串在另一个字符串中的位置。

这个算法明天再写吧,先休息啦

KMP好难,还是先O(mn)正常遍历吧,以后题刷完再回过头来看这个算法叭。下面贴出暴力解法。

public boolean solution(String s1,String s2){
        if(s1==null||s2==null||s1.length()==0||s2.length()==0) return false;
        String s =s2+s2;
//        return getIndexOf(s,s1);// getIndexOf函数通过KMP算法实现
        int i=0;
        int j=0;
        while (i<s1.length()&&j<s.length()){
                if(s1.charAt(i)==s.charAt(j)){
                    i++;
                    j++;
                }
                else {
                   j=j-i+1;
                   i=0;
                }
        }
        return i==s1.length();
    }

3.将整数字符串转成整数值

首先判断字符串是否能对应一个整数,然后进行转化。

判断是否能对应一个整数,应该考虑不满足的四种情形:

1)如果第一个字符不是"-",后面的字符如果不在"0"-"9"之间,肯定不是一个整数字符串。

2)如果第一个字符是"-",字符串长度是1或者第二个字符是"0",肯定不是一个整数字符串。

3)如果第一个字符是"0",并且字符串长度大于1,肯定不是一个整数字符串。

然后跟据字符串的每一位,把数计算出来,这里数可能超过int能表达的范围,所以我这里使用long来保存转换后的值,如果超过了int能表达的范围,就返回0。

public boolean isValid(String s){
        if(s.charAt(0)!='-'&&(s.charAt(0)<'0'||s.charAt(0)>'9')) return false;
        if(s.charAt(0)=='-'&&(s.length()==1||s.charAt(1)=='0')) return false;
        if(s.charAt(0)=='0'&&s.length()>1) return false;
        for(int i=0;i<s.length();i++){
            if(s.charAt(i)>'9'||s.charAt(i)<'0') return false;
        }
        return true;
    }

    public int solution(String s){
        if(s==null||s.length()==0) return 0;
        if(!isValid(s)) return 0;
        boolean position = s.charAt(0)=='-';
        long sum=0 ;
        for(int i=position?1:0;i<s.length();i++){
             int cur =s.charAt(i)-'0';
             sum=sum*10+cur;
        }
        sum=position?-sum:sum;
        if(sum>Integer.MAX_VALUE||sum<Integer.MIN_VALUE) return 0;
        return (int)sum;
    }
发布了24 篇原创文章 · 获赞 3 · 访问量 1301

猜你喜欢

转载自blog.csdn.net/qinian_ztc/article/details/104958085