Java从0开始学习系列之路(2)

朋友来福州找我玩,周五晚上和周末都在外面愉快的玩耍,荒废了博客,有点惭愧啊,,,感觉对不起博客。。

今天主要是根据《代码面试指南》中的第一题来认识一下类中方法的使用,更重要一点是能巩固一下数据结构的知识,感觉这是最重要的东西,好久没接触了,原来就菜得不行,现在更菜了(More vegetable !)。

题目要求:

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

设计要求:

pop,push的操作复杂度都是O(1),getmin的操作复杂度也必须为O(1)。

思路分析:

这题目,要是放在用C/C++,一个最暴力的方法就是用数组模拟栈,每次getmin使都通过遍历数组, 但是如果用容器或者是现成的类来写的话,一般是不支持对栈进行遍历的,一般只允许对栈顶的元素进行处理,而且这种getmin的复杂度是O(n) (这里的n是栈中的元素个数)。

emmm. 我们可以用两个栈,其中一个栈用来正常存储元素,这个栈我们称之为stackDate, 另一个栈我们用来存储当前stackDate中的最小值,我们称之为stackMin。在这边,用个数学式子就可以清楚的表示出这个getmin的原理是啥了:

假设stackDate当前有 i个元素 (   1<= i  ),  如果现在要push入一个newNum, 那么大伙想一想,push之后,stackDate中的最小值是不是:  newMin = min(newNum , stackMin栈顶的元素),说白了也就是,新的最小值将会是前i个数的最小值,newNum这两者中当前较小的数。

伪代码:

  push规则:
  stackDate.push(newNum);

  if( stackDate 为空)
    stackMin.push(newNum );   


  else
  {
      if( newNum <= stackMin栈顶的元素 )
         stackMin.push(newNum);            //这说明了前i+1个数的最小值等于第i+1个元素
   }



  
  pop规则:

  if(stackDate 为空)
     cout << "stackDate is 空" << endl;
 
  else
  {                                                  //这里stackDate栈顶的元素只可能<=stackMin栈顶的元素
       
       if(stackDate栈顶的元素 > stackMin栈顶的元素 ) 
          stackDate.pop();
        
        else if (stackDate栈顶的元素 == stackMin栈顶的元素)//说明当前stackMin栈顶的元素就是由当前stackDate
                                                           // 栈顶的元素贡献的。
               stackDate.pop(), stackMin.pop();
  }

复杂度分析:

只要按照上诉规则在push和pop的过程始终维护stackMin,stackDate栈中的最小值就始终等于stackMin的栈顶元素。

所以getMin 的操作复杂度就是等于O(1)。

附Java代码:

package code_180;

import java.util.*;
import java.util.Stack;
public class stack_Min {

	private Stack<Integer> stackDate ;
	private Stack<Integer> stackMin;
	
	  stack_Min(){
		this.stackDate = new Stack<Integer>();
		this.stackMin = new Stack<Integer>();
	}
	
	public void push( int newNum) {
		
		this.stackDate.push(newNum);
		
		if(this.stackMin.empty() ) 
			 this.stackMin.push(newNum);
		else {
			if(newNum <= this.stackMin.peek() )
				this.stackMin.push(newNum);
		}

			
	}
	
	public void pop() {
		
		if( this.stackDate.isEmpty() == false ) {
		
			
			if(  this.stackDate.peek() == this.stackMin.peek()) {
				
				this.stackMin.pop();
				//System.out.println("ok");
			}
			

			
				
		}
			
		
	}
	
	public int getMin() {
		
		if(this.stackMin.empty() == false )
		   return this.stackMin.peek();
		else
			throw new RuntimeException("Your task is empty");
		
	}
	

	
	public static void main(String[] args) {
		// TODO Auto-generated method stub

           stack_Min stackMy = new stack_Min();
           
           
           int []arrayTest = {3,4,5,1,2,1};
           
           for(int i = 0 ;i < arrayTest.length; i++)
           {
        	   stackMy.push( arrayTest[i]);

           
           System.out.println(stackMy.getMin() + "-----------");
           }
           for(int i = 0 ;i < arrayTest.length; i++)
           {
        	   stackMy.pop();

           
             System.out.println(stackMy.getMin() + "+++++++");
           }
         
           System.out.println(stackMy.getMin());
           
           
        	   
      }

	
	



}

从中学到的一些东西:

1.不添加任何访问权限限定的成员采用的是默认的访问权限。称为default或package,default权限意味着可以被这个类bens

和同一个包的类访问。

2.  java中的方法应该保证在任何情况下都有返回值,这是和c/c++ 区别蛮大的一点:

例如:

public class Test{

  int example(boolean num){
  
   if(num == true )
      return 1;

  }
}

在这种情况下是会错误的,因为num== false的情况下,该函数没有返回值。如果不想在
num == false的情况下返回int.

我们可以throw 一个 RuntimeException(),更改如下:
public class Test{

  public int example(boolean num){
  
   if(num == true )
      return 1;
   else
       throw new RuntimeException("Your task is empty");
       //当然了,返回的内容可以自定义。
  }
}

3.错误类型 java.lang.NullPointerException中的一种情况。
new某个类的实例对象时,如果有成员本身就是个类,那么要在构造函数中写new改成员类的语句,不然默认的构造函数是

无法帮你实例出一个成员的类,如上面双栈的题目中的

      stack_Min(){
        this.stackDate = new Stack<Integer>();
        this.stackMin = new Stack<Integer>();
    }

4.静态方法只能直接访问静态变量或者方法,如果要访问非静态变量或者方法的话,应该在静态方法中new 一个该类的对象,然后用 对象名.方法名()来调用。

而非静态方法即可以直接访问静态变量或者方法,又可以直接访问非静态方法或者变量。

5.在java中为什么main方法必须是静态的解释

因为java都是以类组织在一起的,当我们运行某个程序的时候,我们并不知道这个main方法放在那个类中,也不知道是否要产生一个类的对象,所以,为了解决这个问题我们将main方法定义为static的,这样的话当我们在执行一个java代码的时候,编译器就会在类中去寻找静态的main方法,而不产生类的对象,当JVM加载类的时候main方法自然也就被加载了而用来作为程序的入口。



  •  

猜你喜欢

转载自blog.csdn.net/CCSGTC/article/details/82591544
今日推荐