LeetCode 100题(1)(10题)
1 : 160. 相交链表 - 力扣(LeetCode)
题意:给定两个链表,让你返回这两个链表相交的起始节点,没有就返回null;
思路:我们让 pa 指向 A 链表的头节点,pb 指向 B 链表的头节点,然后每次都移动一个单位长度,假如 pa 移动到 A 链表的尾节点时,就让他指向 B 链表的头节点,同理,当 pb 指向 B 链表的尾节点时,就让它指向 A 链表的头节点。
我们仔细想一下,如果这两个链表后面相交的话,那么 pa 跑完一遍 A 链表,再从 B 链表的头节点跑到两个链表相交的起始节点 和 pb 跑完一遍 B 链表,再从 A 链表的头节点跑到两个链表相交的起始节点,这二者所走过的单位距离一定是相等的。
那么如果这两个链表不相交呢?会不会死循环呢?答案是不会的,他们会在两个链表长度的最大=小公倍数那里同时指向null,退出循环。
时间复杂度O(n);
/*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode(int x) {* val = x;* next = null;* }* }*/
public class Solution {public ListNode getIntersectionNode(ListNode headA, ListNode headB) {ListNode pa = headA;ListNode pb = headB;if(pa == null || pb == null) return null;while(pa != pb){pa = pa == null ? headB : pa.next;pb = pb == null ? headA : pb.next;}return pa;}
}
2:1. 两数之和 - 力扣(LeetCode)
题意:给定一个数组,和一个目标数target,让你找到两个数,使他们加起来等于target,并输出这两个数的下标,保证有解。
思路:我们遍历数组,对于每个数 num1,用 target - num1,表示出我们要找的数num2,然后如果这个数不在 HashMap 里我们就把这个数和它的下标存进去,否则我们就取出这个数的下标 break 这是个在线做法。
那么我们为什么不一开始就存入每个数的下标呢(离线)?因为数组里面会有重复的数
class Solution {public int[] twoSum(int[] nums, int target) {Map<Integer, Integer> mp = new HashMap<>();int x = -1, y = -1;for(int i = 0; i < nums.length; i ++){int num1 = nums[i];int num2 = target - num1;if(mp.containsKey(num2)){x = i;y = mp.get(num2);break;}mp.put(nums[i], i);}return new int[]{x, y};}
}
3: 236. 二叉树的最近公共祖先 - 力扣(LeetCode)
题意:很简单,给定一个二叉树,再给定两个节点p, q,求这两个节点的公共祖先
思路:当一个节点的左子树 lson 中有 p 或 q 节点,我们就设其为 true,右子树 rson 同理,当然如果该节点本身就是 p 或 q, 我们设其为 true,所以最后如果这个节点是最近公共祖先,他要满足的条件就是 :
lson && rson || ((root.val == p.val && (lson || rson)) || (root.val == q.val && (lson || rson)))
详情见代码
/*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode(int x) { val = x; }* }*/
class Solution {static TreeNode ans = null;private boolean dfs(TreeNode root, TreeNode p, TreeNode q){if(root == null) return false;boolean lson = dfs(root.left, p, q);boolean rson = dfs(root.right, p, q);if(lson && rson || ((root.val == p.val && (lson || rson)) || (root.val == q.val && (lson || rson)))){ans = root;}return lson || rson || root.val == p.val || root.val == q.val;}public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {dfs(root, p, q);return ans;}
}
补充:当然这是二叉树的情况,如果是多叉树呢?
P3379 【模板】最近公共祖先(LCA) - 洛谷
我们要用倍增法和 dp 的思想,预处理;
#include <iostream>
#include <vector>
#define int long long
using namespace std;const int N = 5e5 + 10;
vector<vector<int>> e(N);
vector<vector<int>> p(N, vector<int>(21, 0));
vector<int> d(N, 0); // 深度void dfs(int u, int fa)
{p[u][0] = fa;d[u] = d[fa] + 1;for(int i = 1; (1 << i) <= d[u]; i ++){p[u][i] = p[p[u][i - 1]][i - 1];}for(auto v : e[u]){if(v != fa) dfs(v, u);}
}signed main()
{ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int n, m, s;cin >> n >> m >> s;for(int i = 0; i < n - 1; i ++){int u, v;cin >> u >> v;e[u].push_back(v);e[v].push_back(u);}dfs(s, 0);while(m --){int a, b;cin >> a >> b;if(d[a] > d[b]) swap(a, b);for(int i = 20; i >= 0; i --){if(d[b] - (1 << i) >= d[a]){b = p[b][i];}}if(a == b) cout << a << '\n';else{for(int i = 20; i >= 0; i --){if(p[a][i] != p[b][i]){a = p[a][i];b = p[b][i];}}cout << p[a][0] << '\n';}}return 0;
}
4:234. 回文链表 - 力扣(LeetCode)
题意:给定一个链表,判断是否为回文链表;
思路:把链表中的 val 复制到一个数组中,然后用双指针判断即可
/*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val = val; }* ListNode(int val, ListNode next) { this.val = val; this.next = next; }* }*/
class Solution {public boolean isPalindrome(ListNode head) {List<Integer> vec = new ArrayList<>();while(head != null){vec.add(head.val);head = head.next;}boolean f = true;int j = vec.size() - 1;int i = 0;while(i < j){if(!vec.get(i).equals(vec.get(j))){f = false;break;}i ++;j --;}return f;}
}
5:739. 每日温度 - 力扣(LeetCode)
题意:给定一串数组,对于其中每个数,判断后面比它大且离他最近的那个数离它有多远。
思路:单调栈板子题
class Solution {public int[] dailyTemperatures(int[] temperatures) {int len = temperatures.length;int[] ans = new int[len];Stack<Integer> stack = new Stack<>();for(int i = len - 1; i >= 0; i --){while(!stack.isEmpty() && temperatures[stack.peek()] <= temperatures[i]) stack.pop();if(stack.isEmpty()) ans[i] = 0;else{int pos = stack.peek();ans[i] = pos - i;}stack.push(i);}return ans;}
}
6:226. 翻转二叉树 - 力扣(LeetCode)
题意:给你一个二叉树,反转二叉树
思路:递归
/*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val = val; }* TreeNode(int val, TreeNode left, TreeNode right) {* this.val = val;* this.left = left;* this.right = right;* }* }*/
class Solution {private TreeNode dfs(TreeNode root){if(root == null){return null;}TreeNode tmp = root.right;root.right = root.left;root.left = tmp;dfs(root.left);dfs(root.right);return root;}public TreeNode invertTree(TreeNode root) {dfs(root);return root;}
}
7:221. 最大正方形 - 力扣(LeetCode)
题意:给定一个 0 1 矩阵,让你算出矩阵中只包含 1 的正方形;
思路:考虑dp,dp[i][j]表示,以 i, j 坐标为右下角的正方型的最大边长,具体状态转移见代码
class Solution {public int maximalSquare(char[][] matrix) {int rows = matrix.length;int cols = matrix[0].length;int [][] dp = new int[rows + 1][cols + 1];int maxsize = 0;for(int i = 0; i < rows; i ++){for(int j = 0; j < cols; j ++){if(matrix[i][j] == '1'){if((i == 0 || j == 0)){dp[i][j] = 1;}else{dp[i][j] = Math.min(dp[i - 1][j], Math.min(dp[i][j - 1], dp[i - 1][j - 1])) + 1;}}maxsize = Math.max(maxsize, dp[i][j]);}}return maxsize * maxsize;}
}
8:215. 数组中的第K个最大元素 - 力扣(LeetCode)
题意:给定一串数组,让你求出第K大的元素是什么。
思路:最简单的方法就是直接暴力排序,但是时间复杂度是O(nlogn),但我们可以用快速排序(分治)的思想,每次选个轴点,然后经过一轮分类后,这个轴点左边的元素都是小于它的,右边的元素都是大于它的,所以这个轴点的下标 j 就是排名第 j 的元素,然后如果这个排名 j 比我们要的排名高,那就继续排序左边的区间,否则就排序右边的区间。
class Solution {private int quick_sort(int[] nums, int l, int r, int q){if(l == r) return nums[q];int x = nums[(l + r) / 2];int i = l - 1, j = r + 1;while(i < j){do i ++; while(nums[i] < x);do j --; while(nums[j] > x);if(i < j){int tmp = nums[i];nums[i] = nums[j];nums[j] = tmp;}}if(q <= j) return quick_sort(nums, l, j, q);else return quick_sort(nums, j + 1, r, q);}public int findKthLargest(int[] nums, int k) {int n = nums.length;return quick_sort(nums, 0, n - 1, n - k);}
}
9:208. 实现 Trie (前缀树) - 力扣(LeetCode)
题意:实现字典树的增,查功能
思路:板子
class Trie {private Trie[] children;private boolean isEnd;public Trie() {this.children = new Trie[26];this.isEnd = false;}public void insert(String word) {Trie node = this;for(char c : word.toCharArray()){int idx = c - 'a';if(node.children[idx] == null){node.children[idx] = new Trie();}node = node.children[idx];}node.isEnd = true;}public boolean search(String word) {Trie f = checkPrefix(word);return f != null && f.isEnd;}public boolean startsWith(String prefix) {return checkPrefix(prefix) != null;}public Trie checkPrefix(String word){Trie node = this;for(char c : word.toCharArray()){int idx = c - 'a';if(node.children[idx] == null) return null;node = node.children[idx];}return node;}
}/*** Your Trie object will be instantiated and called as such:* Trie obj = new Trie();* obj.insert(word);* boolean param_2 = obj.search(word);* boolean param_3 = obj.startsWith(prefix);*/
10:207. 课程表 - 力扣(LeetCode)
题意:给定num节课,以及几对先修课程的关系,如果一门课程有先修课程,那么必须要先学完先修课程,才能学这门课程,让你判断有没有可能学完所以课程。
思路:我们可以通过题目给的样例看出来,如果不满足情况,那么就意味有自相矛盾的地方,这在图论中就意味着有环存在,我们可以通过简单的拓扑排序判断有无环
class Solution {public boolean canFinish(int numCourses, int[][] prerequisites) {List<Integer> []e = new ArrayList[numCourses];for(int i = 0; i < numCourses; i ++){e[i] = new ArrayList<>();}int[] ind = new int[numCourses];int cnt = 0;Queue<Integer> q = new LinkedList<>();for(int[] info : prerequisites){int u = info[1];int v = info[0];e[u].add(v);ind[v] ++;}for(int i = 0; i < numCourses; i ++){if(ind[i] == 0){q.add(i);}}while(!q.isEmpty()){cnt ++;int t = q.poll();for(int v : e[t]){ind[v] --;if(ind[v] == 0){q.add(v);}}}return cnt == numCourses;}
}