关于链表的操作
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
- 输入一个链表,按链表值从尾到头的顺序返回一个ArrayList
// 利用递归 public class Solution { ArrayList<Integer> list = new ArrayList<Integer>(); public ArrayList<Integer> printListFromTailToHead(ListNode listNode) { if (listNode != null){ printListFromTailToHead(listNode.next); list.add(listNode.val); } return list; } }
-
判断链表是否有环
public boolean hasCycle(ListNode head){ Set<ListNode> set = new HashSet<>(); while (head != null){ if (set.contains(head)){ return true; } else { set.add(head); } head = head.next; } return false; }
利用set的不重复性
-
给定一个链表,返回链表开始入环的第一个节点,如果链表无环,则返回null
public class Solution { public ListNode detectCycle(ListNode head) { Set<ListNode> visited = new HashSet<ListNode>(); ListNode node = head; while (node != null) { if (visited.contains(node)) { return node; } visited.add(node); node = node.next; } return null; } }
与上面的一样
-
在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5
class Solution { public ListNode deleteDuplicates(ListNode head) { if (head == null) return null; ListNode dummy = new ListNode(-1000); dummy.next = head; ListNode node = head; ListNode pre = dummy; while (node!=null){ while (node.next!=null && node.val==node.next.val){ node = node.next; } if (pre.next == node) pre = pre.next; //没有重复元素 else pre.next = node.next; //有重复元素 pre指向不重复的元素 node = node.next; } return dummy.next; } }
设定一个虚拟头结点
-
给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次
1->1->2 输出 1->2class Solution { public ListNode deleteDuplicates(ListNode head) { ListNode node = head; while (node != null){ while (node.next!=null){ if (node.val == node.next.val){ ListNode n = node.next; node.next = n.next; n.next = null; } else { break; } } node = node.next; } return head; } }
内边循环保证当前元素与下个元素不相等,外边元素进行Node的遍历
-
合并两个有序列表
public ListNode mergeTwoLists(ListNode l1, ListNode l2){ if (l1 = null) return l2; if (l2 = null) return l1; if (l1.val < l2.val){ l1.next = mergeTwoLists(l1.next, l2); return l1; } else { l2.next = mergeTwoLists(l1, l2.next); return l2; } }
递归三要素:1.终止条件 2.返回值 3.本级递归内容
-
删除链表倒数第N个节点
public ListNode removeNthFromEnd(ListNode head, int n) { ListNode dummy = new ListNode(0); dummy.next = head; int length = 0; ListNode first = head; while (first != null) { length++; first = first.next; } length -= n; first = dummy; while (length > 0) { length--; first = first.next; } first.next = first.next.next; return dummy.next; }
同样需要一个虚拟头结点
-
旋转链表:给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数。
class Solution { public ListNode rotateRight(ListNode head, int k) { // base cases if (head == null) return null; if (head.next == null) return head; // close the linked list into the ring ListNode old_tail = head; int n; for(n = 1; old_tail.next != null; n++) old_tail = old_tail.next; old_tail.next = head; // find new tail : (n - k % n - 1)th node // and new head : (n - k % n)th node ListNode new_tail = head; for (int i = 0; i < n - k % n - 1; i++) new_tail = new_tail.next; ListNode new_head = new_tail.next; // break the ring new_tail.next = null; return new_head; } }
1.将链表闭合成环 2.找到相应的位置断开这个环,确定新的链表头和链表尾
-
反转链表
public ListNode reverseList(ListNode head) { ListNode prev = null; ListNode curr = head; while (curr != null) { ListNode nextTemp = curr.next; curr.next = prev; prev = curr; curr = nextTemp; } return prev; }
在遍历列表时,将当前节点的 next 指针改为指向前一个元素。由于节点没有引用其上一个节点,因此必须事先存储其前一个元素。在更改引用之前,还需要另一个指针来存储下一个节点。不要忘记在最后返回新的头引用!
关于树的操作
/**
* Definition for binary tree
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
1.给定一个二叉树,求它的最小深度。最小深度是从根节点到最近叶子节点的最短路径上的节点数。
public class Solution {
public int run(TreeNode root) {
if (root == null){
return 0;
}
if ((root.left == null) && (root.right == null)){
return 1;
}
if (root.left == null){
return run(root.right)+1;
}
if (root.right == null){
return run(root.left)+1;
}
return Math.min(run(root.left),run(root.right))+1;
}
}
最大深度同样如此,只需改Math.max即可
2.前、中、后序遍历
import java.util.*;
public class Solution {
ArrayList<Integer> list = new ArrayList<Integer>();
public ArrayList<Integer> preorderTraversal(TreeNode root) {
if (root == null) return list;
list.add(root.val); //1 前序在1 中序在23 后序放3后
preorderTraversal(root.left); //2
preorderTraversal(root.right);//3
return list;
}
}
3.给定一个只包含0-9位数字的二叉树,每个根到叶的路径都可以表示一个数字。一个例子是根到叶的路径1->2->3,它表示数字123。求所有根到叶的数的和。
public class Solution {
public int sumNumbers(TreeNode root) {
return dfs(root, 0);
}
public int dfs(TreeNode root, int sum){
if (root == null) return 0;
sum = sum * 10 + root.val;
if (root.left == null && root.right == null) return sum;
return dfs(root.left, sum) + dfs(root.right, sum);
}
}
4.对称二叉树:给定一个二叉树,检查它是否是镜像对称的
public boolean isSymmetric(TreeNode root) {
return isMirror(root, root);
}
public boolean isMirror(TreeNode t1, TreeNode t2) {
if (t1 == null && t2 == null) return true;
if (t1 == null || t2 == null) return false;
return (t1.val == t2.val) && isMirror(t1.right, t2.left)&& isMirror(t1.left, t2.right);
}
两个数互为镜像满足下面的条件:1)它们的两个根结点具有相同的值 2)每个树的右子树都与另一个树的左子树镜像对称
5.给定两个二叉树,编写一个函数来检验它们是否相同。如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。
class Solution {
public boolean isSameTree(TreeNode p, TreeNode q) {
if (p == null && q == null) return true;
if (p == null || q == null) return false;
return (p.val == q.val) && isSameTree(p.left, q.left)&& isSameTree(p.right, q.right);
}
}
与上面异曲同工
6.给定一个二叉树,返回其按层次遍历的节点值。 (即逐层地,从左到右访问所有节点)。
class Solution {
public List<List<Integer>> levelOrder(TreeNode root){
List<List<Integer>> levels = new ArrayList<List<Integer>>();
if (root == null) return levels;
Queue<TreeNode> queue = new LinkedList<TreeNode>(); //存放每一层的节点
queue.add(root);
int level = 0; //代表层数
while (!queue.isEmpty()){
levels.add(new ArrayList<Integer>()); //存放每一层的节点值
int level_length = queue.size();
for(int i=0; i<level_length;i++){
TreeNode node = queue.remove(); //剔除当层节点
levels.get(level).add(node.val);
if (node.left!=null) queue.add(node.left); //加入下一层节点
if (node.right!=null) queue.add(node.right);
}
level++;
}
return levels;
}
}
关键是生成队列,每一次加入一层的节点,然后一边遍历,一边将节点值加入列表,一边加入下一层的节点
7.给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。
class Solution {
public boolean hasPathSum(TreeNode root, int sum){
if (root==null) return false;
sum -= root.val;
if ((root.left==null) && (root.right==null)) return (sum==0);
return hasPathSum(root.left, sum) || hasPathSum(root.right, sum);
}
}
假想成最简单的情况,总共三个节点,具有通用性
8.给定一个二叉树和一个目标和,找到所有从根节点到叶子节点路径总和等于给定目标和的路径。
public class BalancedBinaryTree {
boolean res = true;
public boolean isBalanced(TreeNode root) {
helper(root);
return res;
}
private int helper(TreeNode root) {
if (root == null) return 0;
int left = helper(root.left) + 1;
int right = helper(root.right) + 1;
if (Math.abs(right - left) > 1) res = false;
return Math.max(left, right);
}
}
关键是创建一个全局布尔变量,在不断对左右子树递归的时候都进行一个判断,用来标志是否平衡
9.翻转一颗二叉树
class Solution {
public TreeNode invertTree(TreeNode root) {
if (root == null) return null;
if (root.left==null && root.right==null) return root;
TreeNode l = root.left;
TreeNode r = root.right;
root.left = r;
root.right = l;
invertTree(root.left);
invertTree(root.right);
return root;
}
}