- k个一组翻转链表
与两个一组思路类似,只是我们每次需要判断之后是够有k个,每次需要记录k个中的第一个(新的尾),最后一个(新的头),最后一个的下一个(下次循环的开始),注意翻转链表要传结束位置。
java
class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
ListNode dummy=new ListNode(0,head);
ListNode p1=dummy;
while(true){
ListNode p2=p1.next,p3=p1.next;
int count=0;
while(count!=k&&p2!=null){
p2=p2.next;
count++;
}
if(count==k){
ListNode newhead=reverse(p3,p2);
p1.next=newhead;
p3.next=p2;
p1=p3;
}else{
break;
}
}
return dummy.next;
}
public ListNode reverse(ListNode head,ListNode end){
ListNode pre=null,last=head;
while(last!=end){
ListNode now=last;
last=last.next;
now.next=pre;
pre=now;
}
return pre;
}
}
- 随机链表的复制 三步走 织网(a-b-c a-a.-b-b.-c-c.)-连接(a...random=a...random.next)-结网
注意几个点random可能会空,连接时需要判断,结网时需要判断后面是否还有
java
class Solution {
public Node copyRandomList(Node head) {
if(head==null) return null;
Node p1=head;
while(p1!=null){
Node node=new Node(p1.val);
node.next=p1.next;
node.random=p1.random;
p1.next=node;
p1=p1.next.next;
}
p1=head.next;
while(p1!=null){
if(p1.random!=null) p1.random=p1.random.next;
if(p1.next!=null) p1=p1.next.next;
else break;
}
Node newHead=head.next,p2=head;
p1=head.next;
while(p1!=null){
p2.next=p2.next.next;
p2=p2.next;
if(p1.next!=null){
p1.next=p1.next.next;
p1=p1.next;
}
else break;
}
return newHead;
}
}
- 排序链表
自底向上,枚举step,对于每个step,遍历一遍链表,构造head1和head2,排序,连接
java
class Solution {
public ListNode sortList(ListNode head) {
int len = 0;
ListNode p1 = head, newHead = new ListNode(0, head);
while (p1 != null) {
p1 = p1.next;
len++;
}
for (int i = 1; i < len; i <<= 1) {
p1 = newHead;
ListNode curr = p1.next;
while (curr != null) {
ListNode head1 = curr;
for (int j = 1; j < i && curr != null; j++) {
curr = curr.next;
}
if (curr == null){
p1.next=head1;
break;
}
ListNode head2 = curr.next;
curr.next = null;
curr = head2;
for (int j = 1; j < i && curr != null; j++) {
curr = curr.next;
}
ListNode next = null;
if (curr != null) {
next = curr.next;
curr.next = null;
}
ListNode temp = merge(head1, head2);
p1.next = temp;
while (p1.next != null) {
p1 = p1.next;
}
curr=next;
}
}
return newHead.next;
}
public ListNode merge(ListNode head1, ListNode head2) {
ListNode dummy = new ListNode();
ListNode p1 = dummy;
while (head1 != null && head2 != null) {
if (head1.val >= head2.val) {
p1.next = head2;
head2 = head2.next;
} else {
p1.next = head1;
head1 = head1.next;
}
p1 = p1.next;
}
if (head1 != null)
p1.next = head1;
if (head2 != null)
p1.next = head2;
return dummy.next;
}
}
递归 基本和归并排序一样(考试优先写,不容易错)
java
class Solution {
public ListNode sortList(ListNode head) {
if(head==null) return head;
if(head.next==null) return head;
ListNode fast=head,slow=head;
while(fast.next!=null&&fast.next.next!=null){
fast=fast.next.next;
slow=slow.next;
}
ListNode second=slow.next;
slow.next=null;
ListNode head1=sortList(head);
ListNode head2=sortList(second);
return merge(head1,head2);
}
public ListNode merge(ListNode head1,ListNode head2){
ListNode dummy=new ListNode(),p1=dummy;
while(head1!=null&&head2!=null){
if(head1.val>=head2.val){
p1.next=head2;
head2=head2.next;
}else{
p1.next=head1;
head1=head1.next;
}
p1=p1.next;
}
if(head1!=null) p1.next=head1;
if(head2!=null) p1.next=head2;
return dummy.next;
}
}
- 合并K个升序链表
分治排序,和上道题的思路基本一样
java
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
if(lists.length==0) return null;
return merge(lists,0,lists.length-1);
}
public ListNode merge(ListNode[] lists,int l,int r){
if(l==r) return lists[l];
int mid=(l+r)>>1;
ListNode head1=merge(lists,l,mid);
ListNode head2=merge(lists,mid+1,r);
return mergeTwo(head1,head2);
}
public ListNode mergeTwo(ListNode head1,ListNode head2){
ListNode dummy=new ListNode(),curr=dummy;
while(head1!=null&&head2!=null){
if(head1.val>head2.val){
curr.next=head2;
head2=head2.next;
}else{
curr.next=head1;
head1=head1.next;
}
curr=curr.next;
}
if(head1!=null) curr.next=head1;
if(head2!=null) curr.next=head2;
return dummy.next;
}
}
- LRU缓存
加入虚拟头尾,方便增删
get时,有的话要将节点放到前面
put时,应该先判断是够存在,存在直接修改值,放到前面,不存在加入新元素,判断是否超过容量(是够删除元素)
java
class LRUCache {
private Node head;
private Node tail;
private Map<Integer, Node> map;
private int capacity;
private int count = 0;
public LRUCache(int capacity) {
this.capacity = capacity;
map = new HashMap<>();
head = new Node();
tail = new Node();
head.next = tail;
tail.pre = head;
map.put(-1, head);
map.put(-2, tail);
}
public int get(int key) {
Node node = map.getOrDefault(key, null);
if (node != null) {
remove(node);
addHead(node);
return node.val;
} else
return -1;
}
public void put(int key, int value) {
Node node = map.getOrDefault(key, null);
if (node != null) {
node.val=value;
remove(node);
addHead(node);
return;
}
if (count == capacity) {
map.remove(tail.pre.key);
remove(tail.pre);
count--;
}
node = new Node(key, value);
addHead(node);
map.put(key, node);
count++;
}
public void remove(Node node) {
node.pre.next = node.next;
node.next.pre = node.pre;
}
public void addHead(Node node) {
Node next = head.next;
node.pre = head;
node.next = next;
next.pre = node;
head.next = node;
}
class Node {
public int key;
public int val;
public Node pre;
public Node next;
public Node(int key, int val) {
this.key = key;
this.val = val;
}
public Node() {
}
}
}
- 二叉树中序遍历
Morris 中序遍历思路:当前节点有左子树,我们将左子树最右节点连上当前节点,下次访问到这个节点,我们断开,并将当前结果加入res,继续遍历右子树
java
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res=new ArrayList<>();
while(root!=null){
if(root.left!=null){
TreeNode node=root.left;
while(node.right!=null&&node.right!=root){
node=node.right;
}
if(node.right==null){
node.right=root;
root=root.left;
}else{
node.right=null;
res.add(root.val);
root=root.right;
}
}
else{
res.add(root.val);
root=root.right;
}
}
return res;
}
}
- 二叉树的最大深度
递归
java
class Solution {
public int maxDepth(TreeNode root) {
if(root==null) return 0;
int left=maxDepth(root.left);
int right=maxDepth(root.right);
return Math.max(left+1,right+1);
}
}
- 翻转二叉树
递归
java
class Solution {
public TreeNode invertTree(TreeNode root) {
if(root==null) return null;
TreeNode left=invertTree(root.left);
TreeNode right=invertTree(root.right);
root.left=right;
root.right=left;
return root;
}
}
- 对称二叉树
递归,比的是两个对应点的位置
java
class Solution {
public boolean isSymmetric(TreeNode root) {
return symmetric(root.left, root.right);
}
public boolean symmetric(TreeNode left, TreeNode right) {
if (left == null && right == null)
return true;
if (left != null && right != null) {
boolean l = symmetric(left.left, right.right);
boolean r = symmetric(left.right, right.left);
return l && r && (left.val == right.val);
}
return false;
}
}
迭代
注意用LinkedList(允许加入空值)ArrayDeque不允许空值
java
class Solution {
public boolean isSymmetric(TreeNode root) {
Deque<TreeNode> q=new LinkedList<>();
q.offer(root.left);
q.offer(root.right);
while(!q.isEmpty()){
TreeNode node1=q.pollFirst();
TreeNode node2=q.pollFirst();
if(node1==null&&node2==null) continue;
if(node1==null||node2==null||(node1.val!=node2.val)) return false;
q.offerLast(node1.left);
q.offerLast(node2.right);
q.offerLast(node1.right);
q.offerLast(node2.left);
}
return true;
}
}
二叉树直径
递归当前树的左右节点最大深度(有几个节点)
每次计算当前节点的最大直接,去更新全局最大直径
返回当前节点的最大深度
java
class Solution {
private int cnt=0;
public int diameterOfBinaryTree(TreeNode root) {
diameter(root);
return cnt;
}
public int diameter(TreeNode node){
if(node==null) return 0;
int l=diameter(node.left);
int r=diameter(node.right);
cnt=Math.max(cnt,l+r);
return Math.max(l,r)+1;
}
}