分类
链表
- 题目: 链表求和
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode l = new ListNode(0), h = l;
int c = 0;
while(l1 != null && l2 != null) {
c += l1.val + l2.val;
l.val = c % 10;
c /= 10;
// 当c>0或者(l1或l2)还未遍历结束的时候继续需要生成节点
if(c > 0 || l1.next != null || l2.next != null) {
l.next = new ListNode(0);
l = l.next;
}
l1 = l1.next;
l2 = l2.next;
}
while(l1 != null) {
c += l1.val;
l.val = c % 10;
c /= 10;
if(c > 0 || l1.next != null) {
l.next = new ListNode(0);
l = l.next;
}
l1 = l1.next;
}
while(l2 != null) {
c += l2.val;
l.val = c % 10;
c /= 10;
if(c > 0 || l2.next != null) {
l.next = new ListNode(0);
l = l.next;
}
l2 = l2.next;
}
if(c > 0) {
l.val = c;
}
return h;
}
}
- 回文链表
class Solution {
public boolean isPalindrome(ListNode head) {
if(head == null)
return true;
int len = 0;
ListNode p = head;
while(p != null) {
p = p.next;
len++;
}
p = head;
// 找到中点
for(int i = 0; i < len / 2; i++) {
p = p.next;
}
// 单数要走到链表中点右边
p = len % 2 != 0 ? p.next : p;
// 反转链表
ListNode q = null;
for(ListNode i = p, pre = null, temp = null; i != null; i = temp) {
temp = i.next;
if(temp == null) {
q = i;
}
i.next = pre;
pre = i;
}
p = head;
// 判断
while(q != null && p != null) {
if(q.val != p.val) {
return false;
}
q = q.next;
p = p.next;
}
return true;
}
}
总结:看了官方的题解,感觉我想复杂了,先遍历一遍链表用ArrayList存储链表的值,然后用两个指针,一个指向数组头,一个指向数组尾,进行判断。
- 删除链表中的重复元素
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode deleteDuplicates(ListNode head) {
if(head == null)
return head;
ListNode p = head, q = null;
int k = p.val - 1;
while(p != null) {
if(k != p.val) {
k = p.val;
} else {
// 删除节点
q.next = p.next;
p = q.next;
continue;
}
q = p;
p = p.next;
}
return head;
}
}
/**
* 官方题解
* 作者:LeetCode
* 来源:力扣(LeetCode)
*/
class Right {
public ListNode deleteDuplicates(ListNode head) {
ListNode current = head;
while (current != null && current.next != null) {
if (current.next.val == current.val) {
current.next = current.next.next;
} else {
current = current.next;
}
}
return head;
}
总结:这种写法还是不够优雅,官方题解直接用一个ListNode对象就解决了。
- 环形链表
public class Solution {
public boolean hasCycle(ListNode head) {
if(head == null || head.next == null)
return false;
ArrayList<ListNode> store = new ArrayList<>(200);
while(head != null) {
if(store.contains(head)) {
return true;
}
store.add(head);
head = head.next;
}
return false;
}
}
- 剑指 Offer 06. 从尾到头打印链表
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public int[] reversePrint(ListNode head) {
LinkedList<Integer> stack = new LinkedList<>();
while (head != null) {
stack.push(head.val);
head = head.next;
}
int[] a = new int[stack.size()];
for (int i = 0; i < a.length; i++) {
a[i] = stack.pop();
}
return a;
}
}
很简单的一道题,思路是用栈存储链表的元素,再利用栈先进后出的性质,获取转置后的链表元素
- 两数相加
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
if (l1 == null && l2 == null)
return null;
ListNode curr = new ListNode(0), head = curr, pre = null;
int a = 0;
while (l1 != null && l2 != null) {
a += l1.val + l2.val;
if (pre != null) {
curr = new ListNode(a % 10);
pre.next = curr;
} else {
curr.val = a % 10;
}
pre = curr;
a /= 10;
l1 = l1.next;
l2 = l2.next;
}
while (l1 != null) {
a += l1.val;
curr = new ListNode(a % 10);
pre.next = curr;
pre = curr;
a /= 10;
l1 = l1.next;
}
while (l2 != null) {
a += l2.val;
curr = new ListNode(a % 10);
pre.next = curr;
pre = curr;
a /= 10;
l2 = l2.next;
}
if (a > 0) {
curr = new ListNode(a % 10);
pre.next = curr;
}
return head;
}
}
这道题和链表求和一模一样,官方题解写得很优雅!
- 剑指 Offer 18. 删除链表的节点
class Solution {
public ListNode deleteNode(ListNode head, int val) {
if (head == null)
return null;
if (head.val == val) {
return head.next;
}
ListNode p = head.next, q = head;
while (p != null) {
if (p.val == val) {
q.next = p.next;
break;
}
q = p;
p = p.next;
}
return head;
}
}
栈
- 剑指 Offer 09. 用两个栈实现队列
class CQueue {
private Deque<Integer> stack1;
private Deque<Integer> stack2;
public CQueue() {
stack1 = new LinkedList<>();
stack2 = new LinkedList<>();
}
public void appendTail(int value) {
stack1.push(value);
}
public int deleteHead() {
if(stack2.isEmpty()) {
while(!stack1.isEmpty()) {
stack2.push(stack1.pop());
}
}
if(stack2.isEmpty()) {
return -1;
} else {
return stack2.pop();
}
}
}
这里是看了官方的题解后修改的,我原来想到的是在删除时把stack1的元素装到stack2里, 拿到队列第一个元素后再把stack2的元素装回stack1。看了官方的题解,很巧妙!
树
- 二叉树的中序遍历
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<>();
if (root == null)
return list;
inOrder(root,list);
return list;
}
public void inOrder(TreeNode p, List<Integer> list) {
if (p != null) {
inOrder(p.left, list);
list.add(p.val);
inOrder(p.right, list);
}
}
}
此题还有迭代,Morris算法等解法
- 二叉树的层序遍历
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
if (root == null)
return res;
Deque<TreeNode> queue = new ArrayDeque<>();
TreeNode curr = root, p = root;
int index = -1;
while (curr != null) {
if (curr == p) {
res.add(new ArrayList<>());
index++;
p = null;
}
if (curr.left != null)
queue.offer(curr.left);
if (curr.right != null)
queue.offer(curr.right);
res.get(index).add(curr.val);
if (p == null) {
if (curr.left != null)
p = curr.left;
else if (curr.right != null)
p = curr.right;
}
if (!queue.isEmpty())
curr = queue.poll();
else
curr = null;
}
return res;
}
}
- 二叉树的层次遍历 II
class Solution {
public List<List<Integer>> levelOrderBottom(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
if (root == null)
return res;
Deque<TreeNode> q = new LinkedList<>();
q.offer(root);
TreeNode temp = null;
while (!q.isEmpty()) {
res.add(new ArrayList<>());
int currentSize = q.size();
for (int i = 0; i < currentSize; i++) {
temp = q.poll();
res.get(res.size() - 1).add(temp.val);
if (temp.left != null)
q.offer(temp.left);
if (temp.right != null)
q.offer(temp.right);
}
}
int size = res.size(), count = size / 2;
List<Integer> swap = null;
for (int i = 0; i < count; i++) {
int t = size - 1 - i;
swap = res.get(i);
res.set(i, res.get(t));
res.set(t, swap);
}
return res;
}
}
利用队列的性质,进行层次遍历,可以参考广度优先搜索
- 左叶子之和
class Solution {
public int sumOfLeftLeaves(TreeNode root) {
if(root == null)
return 0;
int sum = 0;
if (root.right != null) {
// 找右子树的叶子节点
sum += sumOfLeftLeaves(root.right);
}
if (root.left != null) {
// 找左子树的叶子节点
sum += sumOfLeftLeaves(root.left);
// 确定左孩子是否为叶子节点
sum += helper(root.left);
}
return sum;
}
public int helper(TreeNode left) {
// 确认是否为叶子节点
if (left.left == null && left.right == null) {
return left.val;
}
return 0;
}
}
- 剑指 Offer 55 - I. 二叉树的深度
class Solution {
public int maxDepth(TreeNode root) {
if (root == null)
return 0;
return 1 + max(maxDepth(root.left), maxDepth(root.right));
}
public static int max(int a, int b) {
return a > b ? a : b;
}
}
利用递归,直接秒了。这道题有多种做法,官方题解就很详细
- 剑指 Offer 27. 二叉树的镜像
class Solution {
public TreeNode mirrorTree(TreeNode root) {
if (root == null)
return null;
helper(root);
return root;
}
public void helper(TreeNode root) {
swap(root);
if (root.left != null)
helper(root.left);
if (root.right != null)
helper(root.right);
}
public void swap(TreeNode root) {
TreeNode temp = root.left;
root.left = root.right;
root.right = temp;
}
}
堆
- 剑指 Offer 40. 最小的k个数
class Solution {
public int[] getLeastNumbers(int[] arr, int k) {
int[] ans = new int[k];
int size = arr.length - 1;
for (int i = (arr.length >> 1) - 1; i >= 0; i--)
helper(arr,i,size);
for (int i = arr.length - 1; i >= 1; i--) {
exchange(arr,0,size);
size--;
helper(arr, 0, size);
}
for (int i = 0; i < k; i++)
ans[i] = arr[arr.length - i - 1];
return ans;
}
private void helper(int[] heap, int i, int size) {
int left = ((i + 1) << 1) - 1, right = (i + 1) << 1, large;
if (left <= size && heap[i] > heap[left])
large = left;
else
large = i;
if (right <= size && heap[large] > heap[right])
large = right;
if (large != i) {
exchange(heap,i,large);
helper(heap, large, size);
}
}
private void exchange(int[] heap, int i, int j) {
int t = heap[i];
heap[i] = heap[j];
heap[j] = t;
}
}
构造最小堆!
其他
- 剑指 Offer 10- I. 斐波那契数列
class Solution {
public int fib(int n) {
if (n == 0 || n == 1)
return n;
final int mod = 1000000007;
int ans = 0, pre = 0, post = 1;
for (int i = 1; i < n; i++) {
ans = pre + post;
if (ans > mod)
ans %= mod;
pre = post;
post = ans;
}
return ans;
}
}
- 剑指 Offer 11. 旋转数组的最小数字
class Solution {
public int minArray(int[] numbers) {
Arrays.sort(numbers);
return numbers[0];
}
}
其实就是求数组的最小值
class Solution {
public int maximum69Number (int num) {
String s = String.valueOf(num);
return Integer.valueOf(s.replaceFirst("6", "9"));
}
}