leetcode题目小结
leetcode 206 反转单链表
给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
思路:使用三个工作指针计为n1、n2、n3,分别指向头结点、头结点下一个结点和空结点,开始时将n1结点的next指针标记为空,断开与后续结点的连接,之后进入循环,n3指针指向n2指针指向的节点的下一个节点,将n2指针的next指针指向n1,n1指针指向n2,n2指针指向n3,循环直至n22为空。
class Solution {
public ListNode reverseList(ListNode head) {
if (head == null || head.next == null) return head;
ListNode n1 = head, n2 = n1.next, n3 = null;
n1.next = null;
while (n2 != null) {
n3 = n2.next;
n2.next = n1;
n1 = n2;
n2 = n3;
}
return n1;
}
}
leetcode 92
给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表
思路:其中反转链表的思路与本文上一题相同,区别在于本题指定的反转链表的范围。自然的想法是,使用两个指针,一个指针指p1向需要反转的链表的第一个结点的前一个结点并将next指针置空,第二个指针p2指向需要反转的链表最后一个结点的后一个结点,再使用一个指针指向需要反转的链表的第一个结点,准备工作结束,开始反转链表,反转链表结束后,将p1指针的next指针指向新的头结点。值得注意的是,为了不考虑left和right的各种情况,使用dummynode这个小技巧。
class Solution {
public ListNode reverseBetween(ListNode head, int left, int right) {
ListNode dummyNode = new ListNode(-1);
dummyNode.next = head;
ListNode pre = dummyNode;
for (int i = 0; i < left-1; i++) {
pre = pre.next;
}
ListNode rightNode = pre;
for (int i = 0; i < right-left+1; i++) {
rightNode = rightNode.next;
}
ListNode leftNode = pre.next;
ListNode cur = rightNode.next;
pre.next = null;
rightNode.next = null;
ListNode n1 = leftNode.next;
leftNode.next = cur;
ListNode n2 = null;
while (n1 != null) {
n2 = n1.next;
n1.next = leftNode;
leftNode = n1;
n1 = n2;
}
pre.next = leftNode;
return dummyNode.next;
}
}
leetcode 138 复制带随机指针的链表
给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。
构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 。
例如,如果原链表中有 X 和 Y 两个节点,其中 X.random --> Y 。那么在复制链表中对应的两个节点 x 和 y ,同样有 x.random --> y 。
返回复制链表的头节点。
用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:
val:一个表示 Node.val 的整数。
random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为 null 。
你的代码 只 接受原链表的头节点 head 作为传入参数。
思路: 这道题按照左神的思路解决。首先,在原始链表中每一个结点的后面添加该结点的复刻结点,但是没有复制随机指针,只复制了结点的值。然后再复制随机指针,将复刻结点的随机指针指向原始随机指针指向结点的复刻结点,最后进行剥离操作,返回结点头指针。值得注意的是,在新旧链表剥离时,使用了dummynode的小技巧。
class Solution {
public Node copyRandomList(Node head) {
if (head == null) return head;
Node p1 = head;
Node p2 = p1;
// 将赋值的节点加载原始结点后一个
while (p1 != null) {
p2 = p1.next;
Node node = new Node(p1.val);
p1.next = node;
node.next = p2;
p1 = p2;
}
// 赋值随机指针
p1 = head;
while (p1 != null) {
p2 = p1.next;
p2.random = p1.random == null ? null : p1.random.next;
p1 = p2.next;
}
// 新旧指针剥离
Node dummyNode = new Node(-1);
Node tail = dummyNode;
p1 = head;
p2 = null;
while (p1 != null) {
p2 = p1.next.next;
tail.next = p1.next;
tail = tail.next;
p1.next = p2;
p1 = p2;
}
return dummyNode.next;
}
}
leetcode 234 回文链表
给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。
class Solution {
public boolean isPalindrome(ListNode head) {
if (head == null || head.next == null) return true;
ListNode fast = head, slow = head;
while (fast.next != null && fast.next.next != null) {
fast = fast.next.next;
slow = slow.next;
}
ListNode h = reverse(slow);
fast = head;
slow = h;
while (fast != null && slow != null) {
if (fast.val != slow.val) return false;
fast = fast.next;
slow = slow.next;
}
reverse(h);
return true;
}
public ListNode reverse(ListNode head) {
if (head == null) return null;
ListNode p1 = head, p2 = p1.next, p3 = null;
p1.next = null;
while (p2 != null) {
p3 = p2.next;
p2.next = p1;
p1 = p2;
p2 = p3;
}
return p1;
}
}
leetcode 86 分隔链表
给你一个链表的头节点 head 和一个特定值 x ,请你对链表进行分隔,使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。
你应当 保留 两个分区中每个节点的初始相对位置。
class Solution {
public ListNode partition(ListNode head, int x) {
ListNode large, small, p, largeHead, smallHead;
large = new ListNode(0);
largeHead = large;
small = new ListNode(0);
smallHead = small;
p = head;
while (p != null) {
if (p.val < x) {
small.next = p;
small = small.next;
}else {
large.next = p;
large = large.next;
}
p = p.next;
}
small.next = largeHead.next;
large.next = null;
return smallHead.next;
}
}
leetcode 144 二叉树的前序遍历
class Solution {
// 非递归方法
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
if (root == null) return res;
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while (!stack.empty()) {
TreeNode tmp = stack.pop();
res.add(tmp.val);
if (tmp.right != null) stack.push(tmp.right);
if (tmp.left != null) stack.push(tmp.left);
}
return res;
}
/** 递归方法 */
public List<Integer> preorderTraversal1(TreeNode root) {
List<Integer> res = new ArrayList<>();
preorder(res, root);
return res;
}
public void preorder(List<Integer> res, TreeNode root) {
if (root == null) return;
res.add(root.val);
preorder(res, root.left);
preorder(res, root.right);
}
}
leetcode 145 二叉树的后序遍历
class Solution {
/** 非递归 */
public List<Integer> postorderTraversal1(TreeNode root) {
List<Integer> res = new ArrayList<>();
if (root == null) return res;
Stack<TreeNode> stack1 = new Stack<>();
Stack<TreeNode> stack2 = new Stack<>();
stack1.push(root);
while (!stack1.empty()) {
TreeNode tmp = stack1.pop();
stack2.push(tmp);
if (tmp.left != null) stack1.push(tmp.left);
if (tmp.right != null) stack1.push(tmp.right);
}
while (!stack2.empty()) {
res.add(stack2.pop().val);
}
return res;
}
/** 递归方法 */
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
postorder(res, root);
return res;
}
public void postorder(List<Integer> res, TreeNode root) {
if (root == null) return;
postorder(res, root.left);
postorder(res, root.right);
res.add(root.val);
}
}
leetcode 94 二叉树的中序遍历
class Solution {
/** 非递归方法 */
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
if (root == null) return res;
Stack<TreeNode> stack = new Stack<>();
while (root != null) {
stack.push(root);
root = root.left;
}
while (!stack.empty()) {
TreeNode tmp = stack.pop();
res.add(tmp.val);
if (tmp.right != null) {
tmp = tmp.right;
while (tmp != null) {
stack.push(tmp);
tmp = tmp.left;
}
}
}
return res;
}
/** 递归方法 */
public List<Integer> inorderTraversal1(TreeNode root) {
List<Integer> res = new ArrayList<>();
inorder(res, root);
return res;
}
public void inorder(List<Integer> res, TreeNode root) {
if (root == null) return;
inorder(res, root.left);
res.add(root.val);
inorder(res, root.right);
}
}
leetcode 102. 二叉树的层序遍历
class Solution {
/** 使用有限个变量代替hashmap */
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
if (root == null) return res;
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
TreeNode curEnd = root;
TreeNode nextEnd = null;
List<Integer> tmpList = new ArrayList<>();
while (!queue.isEmpty()) {
TreeNode tmp = queue.poll();
if (tmp.left != null) {
queue.add(tmp.left);
nextEnd = tmp.left;
}
if (tmp.right != null) {
queue.add(tmp.right);
nextEnd = tmp.right;
}
if (tmp == curEnd) {
tmpList.add(tmp.val);
res.add(tmpList);
curEnd = nextEnd;
nextEnd = null;
tmpList = new ArrayList<>();
}else {
tmpList.add(tmp.val);
}
}
return res;
}
/** 使用额外辅助空间记录每个结点的层数 */
public List<List<Integer>> levelOrder1(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
if (root == null) return res;
Map<TreeNode, Integer> nodeLevel = new HashMap<>();
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
nodeLevel.put(root, 1);
int curLevel = 1;
List<Integer> tmpList = new ArrayList<>();
while (!queue.isEmpty()) {
TreeNode tmp = queue.poll();
int level = nodeLevel.get(tmp);
if (level == curLevel) {
tmpList.add(tmp.val);
}else {
curLevel++;
res.add(tmpList);
tmpList = new ArrayList<>();
tmpList.add(tmp.val);
}
if (tmp.left != null) {
nodeLevel.put(tmp.left, level+1);
queue.add(tmp.left);
}
if (tmp.right != null) {
nodeLevel.put(tmp.right, level+1);
queue.add(tmp.right);
}
}
// 最后一层的数据要单独加入
res.add(tmpList);
return res;
}
}
leetcode 107 二叉树层序遍历II
class Solution {
public List<List<Integer>> levelOrderBottom(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
if (root == null) return res;
Queue<TreeNode> queue = new LinkedList<>();
TreeNode curEnd = root;
TreeNode nextEnd = null;
queue.add(root);
List<Integer> tmpList = new ArrayList<>();
while (!queue.isEmpty()) {
TreeNode tmp = queue.poll();
if (tmp.left != null) {
queue.add(tmp.left);
nextEnd = tmp.left;
}
if (tmp.right != null) {
queue.add(tmp.right);
nextEnd = tmp.right;
}
if (tmp == curEnd) {
tmpList.add(tmp.val);
res.add(tmpList);
curEnd = nextEnd;
nextEnd = null;
tmpList = new ArrayList<>();
}else {
tmpList.add(tmp.val);
}
}
Collections.reverse(res);
return res;
}
}
leetcode 662. 二叉树最大宽度
思路:这道题相比较前面两道二叉树的层序遍历还有有一定难度。在每一层结点个数统计时需要将当前层第一个和最后一个结点之间的null结点计算进去,因此本题的解决方案是为每个结点设置pos属性,记录是第几个节点。
class Solution {
public int widthOfBinaryTree(TreeNode root) {
int res = 0;
if (root == null) return 0;
Queue<MyNode> queue = new LinkedList<>();
queue.add(new MyNode(root, 1));
TreeNode curEnd = root;
TreeNode nextEnd = null;
List<MyNode> tmpList = new ArrayList<>();
int max = -1;
while (!queue.isEmpty()) {
MyNode tmp = queue.poll();
if (tmp.node.left != null) {
queue.add(new MyNode(tmp.node.left, tmp.pos*2));
nextEnd = tmp.node.left;
}
if (tmp.node.right != null) {
queue.add(new MyNode(tmp.node.right, tmp.pos*2 + 1));
nextEnd = tmp.node.right;
}
if (tmp.node == curEnd) {
tmpList.add(tmp);
int num = tmpList.get(tmpList.size()-1).pos - tmpList.get(0).pos + 1;
max = Math.max(max, num);
tmpList = new ArrayList<>();
curEnd = nextEnd;
nextEnd = null;
}else {
tmpList.add(tmp);
}
}
return max;
}
}
class MyNode {
public TreeNode node;
public int pos;
public MyNode (TreeNode node, int pos) {
this.node = node;
this.pos = pos;
}
}