力扣爆刷第163天之TOP100五连刷81-85(回文链表、路径和、最长重复子数组)
文章目录
- 力扣爆刷第163天之TOP100五连刷81-85(回文链表、路径和、最长重复子数组)
- 一、234. 回文链表
- 二、112. 路径总和
- 三、169. 多数元素
- 四、662. 二叉树最大宽度
- 五、718. 最长重复子数组
一、234. 回文链表
题目链接:https://leetcode.cn/problems/palindrome-linked-list/description/
思路:判断链表是否是回文链表,也是经典题目了,一般对于链表来说基本操作就是快慢指针,通过快慢指针寻找链表的中间节点,然后把后一半链表翻转,头插法或者尾插法都可以,这样前一半和后一半的链表都正序了,就可以逐一比较了,只要相等即可。
class Solution {
public boolean isPalindrome(ListNode head) {
ListNode root = new ListNode(-1, head);
ListNode slow = root, fast = root;
while(fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
ListNode t = new ListNode();
fast = slow.next;
slow.next = null;
slow = fast;
while(slow != null) {
ListNode p = slow.next;
slow.next = t.next;
t.next = slow;
slow = p;
}
slow = head;
fast = t.next;
while(fast != null) {
if(slow.val != fast.val) return false;
slow = slow.next;
fast = fast.next;
}
return true;
}
}
二、112. 路径总和
题目链接:https://leetcode.cn/problems/path-sum/description/
思路:求路径总和,也就是存不存在一条路径上的总和等于目标和,这个寻找的过程类似于回溯,找到就OK了,找不到回溯返回,可以把累加和添加在函数的参数里,这样可以省去递归的撤销代码。
class Solution {
boolean flag = false;
public boolean hasPathSum(TreeNode root, int targetSum) {
traverse(root, targetSum, 0);
return flag;
}
void traverse(TreeNode root, int targetSum, int sum) {
if(root == null || flag) return ;
if(root.left == null && root.right == null && sum + root.val == targetSum) flag = true;
traverse(root.left, targetSum, sum + root.val);
traverse(root.right, targetSum, sum + root.val);
}
}
三、169. 多数元素
题目链接:https://leetcode.cn/problems/majority-element/description/
思路:求数组中的多数元素,何为多数元素,即数量超过总个数的一半即为多数,可以利用这一特性,采用计数法,用一个变量计数,另一个变量记录元素值,元素值相同就计数,不同就减,减到0,就替换元素,非常简单,利用计数法。
class Solution {
public int majorityElement(int[] nums) {
int num = 0, t = 0;
for(int i : nums) {
if(num == 0) t = i;
if(i == t) num++;
else num--;
}
return t;
}
}
四、662. 二叉树最大宽度
题目链接:https://leetcode.cn/problems/maximum-width-of-binary-tree/description/
思路:求二叉树的最大宽度,本题对于宽度的定义是每一层中最左边的节点和最右边的节点所组成的区间中的所有节点的个数,包括null节点,所以可以采取给二叉树编码的方式,给每一个节点编码,并且记录下每一层第一个向下突破深度的节点,即可根据节点编号计算宽度。
class Solution {
List<Integer> list = new ArrayList<>();
int max = 1;
public int widthOfBinaryTree(TreeNode root) {
traverse(root, 0, 0);
return max;
}
void traverse(TreeNode root, int id, int deep) {
if(root == null) return ;
if(list.size() == deep) {
list.add(id);
}else{
max = Math.max(max, id - list.get(deep)+1);
}
traverse(root.left, id * 2 + 1, deep + 1);
traverse(root.right, id * 2 + 2, deep + 1);
}
}
五、718. 最长重复子数组
题目链接:https://leetcode.cn/problems/maximum-length-of-repeated-subarray/description/
思路:求最长重复子数组,也是很经典的动态规划题目,子数组是连续的,定义dp[i][j]表示以nums1[i]和nums2[j]为结尾的最长重复子数组的长度,根据定义来看,如果nums1[i] == nums2[j] 那么dp[i][j] = dp[i-1][j-1],这是因为如果结尾相等,那么他们的长度自然依赖于上一个状态,如果不等自然是0。
class Solution {
public int findLength(int[] nums1, int[] nums2) {
int m = nums1.length, n = nums2.length, max = 0;
int[][] dp = new int[m+1][n+1];
for(int i = 0; i < m; i++) {
for(int j = 0; j < n; j++) {
if(nums1[i] == nums2[j]) {
dp[i+1][j+1] = dp[i][j] + 1;
}
if(dp[i+1][j+1] > max) max = dp[i+1][j+1];
}
}
return max;
}
}