目录
栈和队列
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;
}