7月算法训练------第三十一天(状态压缩)解题报告
题目类型:状态压缩
题目难度:中等
第一题、526. 优美的排列
- 题目链接:526. 优美的排列
- 思路分析:
这一题有点难了,没咋看懂 - 代码:
class Solution {
public int countArrangement(int n) {
// visited的最终状态为 (1 << n) - 1
int mask = 1 << n;
int[][] dp = new int[n + 1][mask];
// 初始值,与DFS中所有数都填完了返回1是一样的原理
dp[0][0] = 1;
for (int i = 1; i <= n; i++) {
for (int visited = 0; visited < mask; visited++) {
// 只有 i 与 visited 中1的位数相等时才需要计算
// 因为填写第 1 个数时,不可能已经访问了两个数
if (Integer.bitCount(visited) == i) {
for (int num = 1; num <= n; num++) {
// 第一个条件:与DFS相反,这里表示本次填入了这个数
if (((1 << (num - 1)) & visited) != 0 && (num % i == 0 || i % num == 0)) {
// i - 1位置没有放入num
// 1 << (num - 1) 表示第 num 位是1,取反就是这位是0,其他都是1
// 再与 visited 与运算表示打掉 visited 这位的 1
dp[i][visited] += dp[i - 1][visited & (~(1 << (num - 1)))];
}
}
}
}
}
return dp[n][mask - 1];
}
}
剑指offer
题目类型:双指针
题目难度:简单
第二题、剑指 Offer 25. 合并两个排序的链表
- 题目链接:剑指 Offer 25. 合并两个排序的链表
- 思路分析:
这一题在前一天已经做过了,所以今天十分得心应手,和29号做的第21题一样的:
7月29号题解 - 代码:
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if(l1 == null){
return l2;
}
if(l2 == null){
return l1;
}
ListNode head = new ListNode();
ListNode tail = head;
while(l1 != null && l2 != null){
if(l1.val > l2.val){
ListNode temp = new ListNode(l2.val);
tail.next = temp;
tail = tail.next;
l2 = l2.next;
}else{
ListNode temp = new ListNode(l1.val);
tail.next = temp;
tail = tail.next;
l1 = l1.next;
}
}
if(l1 != null){
tail.next = l1;
}else{
tail.next = l2;
}
return head.next;
}
}
第三题、剑指 Offer 52. 两个链表的第一个公共节点
- 题目链接:剑指 Offer 52. 两个链表的第一个公共节点
- 思路分析:
- 当
headA
或headB
为null
时,说明其中必不可能存在重复节点,直接返回null
。 - 然后用一个hash集合来存储
headA
的所有节点,这就需要遍历一遍headA
。 - 再遍历一遍
headB
的所有节点,如果在hash集合中有重复节点,则将这个节点返回。 - 如果
headA
和headB
中不存在重复节点,则就返回null
。
- 代码:
class Solution {
ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if(headA == null || headB == null) return null;
Set<ListNode> set = new HashSet();
while(headA != null){
set.add(headA);
headA = headA.next;
}
while(headB != null){
if(set.contains(headB)){
return headB;
}
headB = headB.next;
}
return null;
}
}