141. Linked List Cycle
快慢指针相结合,当快指针追上慢指针时,即存在环。
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public boolean hasCycle(ListNode head) {
if(head==null)
return false;
ListNode fast = head;
ListNode slow = head;
while(fast.next!=null && fast.next.next!=null){
fast = fast.next.next;
slow = slow.next;
if(fast==slow)
return true;
}
return false;
}
}
142. Linked List Cycle II
快慢指针相结合,首先,当快指针一次走两步,慢指针一次走一步,快指针追上慢指针时,快指针刚好比慢指针多走了一个环的步数。此时,如果让快指针从head开始一次走一步,慢指针接着往前走,那么两个指针一定会在环开始的位置相遇。
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode detectCycle(ListNode head) {
if(head==null)
return head;
ListNode fast = head;
ListNode slow = head;
int step = 0;
while(fast.next!=null && fast.next.next!=null){
fast = fast.next.next;
slow = slow.next;
if(fast == slow){
fast=head;
while(fast!=slow){
fast = fast.next;
slow = slow.next;
}
return fast;
}
}
return null;
}
}
143. Reorder List
分三步走,对于一个链表 1->2->3->4->5->6来说:
1、找到链表的中间节点,使用快慢指针
2、将链表从中间节点开始进行倒置,即1->2->3->4->5->6 to 1->2->3->6->5->4
3、将链表进行重新排序,即1->2->3->6->5->4 to 1->6->2->5->3->4
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public void reorderList(ListNode head) {
if(head==null||head.next==null) return;
//Find the middle of the list
ListNode p1=head;
ListNode p2=head;
while(p2.next!=null&&p2.next.next!=null){
p1=p1.next;
p2=p2.next.next;
}
//Reverse the half after middle 1->2->3->4->5->6 to 1->2->3->6->5->4
ListNode preMiddle=p1;
ListNode preCurrent=p1.next;
while(preCurrent.next!=null){
ListNode current=preCurrent.next;
preCurrent.next=current.next;
current.next=preMiddle.next;
preMiddle.next=current;
}
//Start reorder one by one 1->2->3->6->5->4 to 1->6->2->5->3->4
p1=head;
p2=preMiddle.next;
while(p1!=preMiddle){
preMiddle.next=p2.next;
p2.next=p1.next;
p1.next=p2;
p1=p2.next;
p2=preMiddle.next;
}
}
}
144. Binary Tree Preorder Traversal
非递归的前序遍历二叉树,根据前序遍历访问的顺序,优先访问根结点,然后再分别访问左孩子和右孩子。即对于任一结点,其可看做是根结点,因此可以直接访问,访问完之后,若其左孩子不为空,按相同规则访问它的左子树;当访问其左子树时,再访问它的右子树。因此其处理过程如下:
对于任一结点P:
(1)访问结点P,并将结点P入栈;
(2)判断结点P的左孩子是否为空,若为空,则取栈顶结点并进行出栈操作,并将栈顶结点的右孩子置为当前的结点P,循环至1);若不为空,则将P的左孩子置为当前的结点P;
(3)直到P为NULL并且栈为空,则遍历结束。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public List preorderTraversal(TreeNode root) {
List res = new ArrayList();
if(root==null)
return res;
Stack stack = new Stack();
stack.push(root);
while(!stack.empty()){
TreeNode top = stack.pop();
res.add(top.val);
if(top.right!=null)
stack.push(top.right);
if(top.left!=null)
stack.push(top.left);
}
return res;
}
}
145. Binary Tree Postorder Traversal
后序遍历的非递归实现是三种遍历方式中最难的一种。因为在后序遍历中,要保证左孩子和右孩子都已被访问并且左孩子在右孩子前访问才能访问根结点,这就为流程的控制带来了难题。下面介绍两种思路。
第一种思路:对于任一结点P,将其入栈,然后沿其左子树一直往下搜索,直到搜索到没有左孩子的结点,此时该结点出现在栈顶,但是此时不能将其出栈并访问,因此其右孩子还为被访问。所以接下来按照相同的规则对其右子树进行相同的处理,当访问完其右孩子时,该结点又出现在栈顶,此时可以将其出栈并访问。这样就保证了正确的访问顺序。可以看出,在这个过程中,每个结点都两次出现在栈顶,只有在第二次出现在栈顶时,才能访问它。因此需要多设置一个变量标识该结点是否是第一次出现在栈顶。
第二种思路:要保证根结点在左孩子和右孩子访问之后才能访问,因此对于任一结点P,先将其入栈。如果P不存在左孩子和右孩子,则可以直接访问它;或者P存在左孩子或者右孩子,但是其左孩子和右孩子都已被访问过了,则同样可以直接访问该结点。若非上述两种情况,则将P的右孩子和左孩子依次入栈,这样就保证了每次取栈顶元素的时候,左孩子在右孩子前面被访问,左孩子和右孩子都在根结点前面被访问。
这里我们实现的是第一种思路,用一个辅助的stack来标记当前节点第几次出现在栈顶。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public List postorderTraversal(TreeNode root) {
List res = new ArrayList();
if(root==null)
return res;
Stack stack = new Stack();
Stack flag = new Stack();
TreeNode p = root;
while(p!=null){
stack.push(p);
flag.push(0);
p = p.left;
}
while(!stack.empty()){
TreeNode temp = stack.pop();
int times = flag.pop();
if(times==0){
flag.push(1);
stack.push(temp);
temp = temp.right;
while(temp!=null){
stack.push(temp);
flag.push(0);
temp = temp.left;
}
}
else
res.add(temp.val);
}
return res;
}
}
147. Insertion Sort List
实现链表上的直接插入排序。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode insertionSortList(ListNode head) {
ListNode helper=new ListNode(0);
ListNode pre=helper;
ListNode current=head;
while(current!=null) {
pre=helper;
while(pre.next!=null&&pre.next.val
150. Evaluate Reverse Polish Notation
使用一个栈
class Solution {
public int evalRPN(String[] tokens) {
if(tokens==null || tokens.length==0)
return 0;
Stack stack = new Stack();
for(String str:tokens){
if(str.equals("+")){
int l1 = Integer.parseInt(stack.pop());
int l2 = Integer.parseInt(stack.pop());
stack.push((l1+l2)+"");
}
else if(str.equals("*")){
int l1 = Integer.parseInt(stack.pop());
int l2 = Integer.parseInt(stack.pop());
stack.push((l1*l2)+"");
}
else if(str.equals("-")){
int l1 = Integer.parseInt(stack.pop());
int l2 = Integer.parseInt(stack.pop());
stack.push((l2-l1)+"");
}
else if(str.equals("/")){
int l1 = Integer.parseInt(stack.pop());
int l2 = Integer.parseInt(stack.pop());
stack.push((l2/l1)+"");
}
else
stack.push(str);
}
return Integer.parseInt(stack.pop());
}
}