双指针总结
数组篇
数组
通过两个指针在一个for循环下完成两个for循环的工作。
字符串
原地反转字符串:字符串:这道题目,使用库函数一行代码搞定,使用前后两个指针,使用swap的方式将元素交换
原地替换空格:对于java而言,先使用一个StringBuilder将应该给String类型扩容的大小记录下来,加在原来的String类型的后面,使用toCharArray()的方式转换成char[],再使用两个指针,一个指向该string的末尾,一个指向该string的原字符串的末尾的位置,从后往前进行替换。
字符串:花式反转:反转字符串中单词的顺序,其中存在冗余的空格,首先将多余的空格删除,可以分成三部分,单词前的,单词末尾的,单词之间的。然后先将整个字符串翻转,再将每个单词翻转。复杂度为O(n)
链表:
反转链表:只需要改变链表的next指针的指向,直接将链表反转 ,而不用重新定义一个新的链表。也可以采用递归的方式,
ListNode list= reverseList(head.next);
head.next.next=head;
head.next=null;
list返回的头节点,而head.next为新节点的尾节点,将其next指向head,并且将head的next重置,避免形成环。
判断环形链表及其环起点
使用快慢指针,快指针两倍速前进,当快慢指针相遇时,必在环中,此时将快慢指针的任一个从头结点重新出发,重新相遇的节点即环入口。
N数之和
2数之和:使用哈希法,将已出现过的数存在map中,并且要记录下标
3数之和:先排序数组,使用双指针的方式,left指向i的下一位,right指向size-1,然后三个位置的和如果大于0,则right–,小于0则left++,如果等于0,那么left++,right–;同时双指针的移动放在while循环中进行,只要left<right,循环还是继续执行。需要注意此处需要剪枝操作,因为不需要重复的数据,当left++和right–原本的数据相同时,要跳过该位置
4数之和:和3数之和思想完全相同,对相应位置需要进行剪枝
栈与队列
Java中栈和队列的基本信息
队列
Queue队列
Queue的6个方法分类:
压入元素(添加):add()、offer()
相同:未超出容量,从队尾压入元素,返回压入的那个元素。
区别:在超出容量时,add()方法会对抛出异常,offer()返回false
弹出元素(删除):remove()、poll()
相同:容量大于0的时候,删除并返回队头被删除的那个元素。
区别:在容量为0的时候,remove()会抛出异常,poll()返回false
获取队头元素(不删除):element()、peek()
相同:容量大于0的时候,都返回队头元素。但是不删除。
区别:容量为0的时候,element()会抛出异常,peek()返回null。
双端队列
deque 是“double ended queue(双端队列)”的缩写,通常读为“deck”。双端队列顾名思义就是队列的两个端口都能进出。
Deque的实现类是LinkedList,ArrayDeque,LinkedBlockingDeque,其中LinkedList是最常用的。值得注意的是,LinkedList也实现了List接口。
大多数Deque既可以是有容量限制也可以是无固定容量限制。
阻塞队列
阻塞队列是一个支持两个附加操作的队列,即在队列为满时,存储元素的线程会等待队列可用,当队列为空时,获取元素的线程会等待队列为非空。
阻塞队列接口有BlockingQueue和BlockingDeque两个,其中后者是双向队列。
题目
用栈实现队列
请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty):
实现 MyQueue 类:
void push(int x) 将元素 x 推到队列的末尾
int pop() 从队列的开头移除并返回元素
int peek() 返回队列开头的元素
boolean empty() 如果队列为空,返回 true ;否则,返回 false
说明:
你 只能 使用标准的栈操作 —— 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。
你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。
class MyQueue {
Stack<Integer> inStack;
Stack<Integer> outStack;
public MyQueue() {
inStack=new Stack<>();
outStack=new Stack<>();
}
public void push(int x) {
inStack.push(x);
}
public int pop() {
//如果出栈是空的,那么将inStack的数据全部导入
if(outStack.isEmpty()){
while(!inStack.isEmpty()){
int num=inStack.pop();
outStack.push(num);
}
}
return outStack.pop();
}
public int peek() {
if(outStack.isEmpty()){
while(!inStack.isEmpty()){
int num=inStack.pop();
outStack.push(num);
}
}
return outStack.peek();
}
public boolean empty() {
if(inStack.isEmpty()&& outStack.isEmpty()){
return true;
}else{
return false;
}
}
}
/**
* Your MyQueue object will be instantiated and called as such:
* MyQueue obj = new MyQueue();
* obj.push(x);
* int param_2 = obj.pop();
* int param_3 = obj.peek();
* boolean param_4 = obj.empty();
*/
用对列模拟栈
请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。
实现 MyStack 类:
void push(int x) 将元素 x 压入栈顶。
int pop() 移除并返回栈顶元素。
int top() 返回栈顶元素。
boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。
class MyStack {
private Deque<Integer> deque;
public MyStack() {
deque=new ArrayDeque<>();
}
public void push(int x) {
deque.addLast(x);
}
public int pop() {
return deque.pollLast();
}
public int top() {
return deque.peekLast();
}
public boolean empty() {
return deque.isEmpty();
}
}
/**
* Your MyStack object will be instantiated and called as such:
* MyStack obj = new MyStack();
* obj.push(x);
* int param_2 = obj.pop();
* int param_3 = obj.top();
* boolean param_4 = obj.empty();
*/