day70-day71-day72【代码随想录】二刷链表


前言

1、两两交换链表中的节点
2、删除链表的倒数第N个节点
3、移除重复节点
4、和有限的最长子序列
5、至少有 1 位重复的数字
6、数字 1 的个数
7、2出现的次数
8、无矛盾的最佳球队


一、两两交换链表中的节点(力扣24)【递归】

在这里插入图片描述

分析:
大佬题解
请添加图片描述

/**
 * 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 ListNode swapPairs(ListNode head) {
        if(head==null || head.next==null){
            return head;
        }
        ListNode temp = head.next;
        head.next = swapPairs(temp.next);
        temp.next = head;
        return temp;
    }
}

二、删除链表的倒数第N个节点(力扣19)

在这里插入图片描述
分析:
快慢指针:保证快指针和慢指针之间存在n个结点
之后一起++ 直到fast.next==null时,此时slow指针所指位置就是要删除结点的前一个结点

/**
 * 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 ListNode removeNthFromEnd(ListNode head, int n) {
        //快慢指针 快的先走n+1步 慢指针走1步 之后一起++ 直到快指针==null 
        ListNode dummy = new ListNode(-1,head);
        if(head==null) return null;
        ListNode fast;
        ListNode slow;
        fast = dummy;
        slow = dummy;
        int index =0;
        //fast先走n步
        for(int i=0;i<n;i++){
            fast = fast.next;
        }
        //开始同步 说明找到了要删除指针的钱一个指针
        while(fast.next!=null ){
            fast=fast.next;
            slow = slow.next;
        }
        slow.next = slow.next.next;//删除指针
        return dummy.next;
    }
}

三、移除重复节点(面试题 02.01)【借助HashSet】

在这里插入图片描述

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode removeDuplicateNodes(ListNode head) {

        if(head==null) return head;
        ListNode current = head;
        HashSet<Integer> set = new HashSet<>();
        set.add(current.val);
        while(current!=null && current.next!=null){
            if(set.contains(current.next.val)){
                current.next = current.next.next;
            }else{
                set.add(current.next.val);
                current = current.next;
            }
        }
        return head;
    }
}

四、每日一题day70:和有限的最长子序列(力扣2389)【前缀和+二分】

在这里插入图片描述

class Solution {
    public static int[] answerQueries(int[] nums, int[] queries) {
        int[] res = new int[queries.length];
        int[] pre = new int[nums.length];
        //前缀和+二分
        //1、先排序
        Arrays.sort(nums);
        int sum=0;
        //2、求前缀和
        for(int i=0;i<pre.length;i++){
            sum+=nums[i];
            pre[i] = sum;
        }
        //3、求结果 返回下标

        for(int i=0;i<queries.length;i++){
            if(queries[i]<pre[0]){
                res[i] =0;
            }
            else if(queries[i]>pre[pre.length-1]){
                res[i] =pre.length;
            }else {
                int left = 0;
                int right = pre.length - 1;
                int middle;
                int index = 0;
                //二分查找
                while (left <= right) {
                    middle = (left + right) / 2;
                    if (pre[middle] >queries[i]) {

                        right = middle - 1;
                    }
                    if (pre[middle] <= queries[i]) {
                        index = middle+1;
                        left = middle + 1;
                    }
                }
                res[i] = index;
            }
        }
        return res;
    }
}

五、每日一题day71:至少有 1 位重复的数字(力扣1012)【数位DP】

在这里插入图片描述
分析:
大佬题解

class Solution {

    char s[];
    int memo[][];
    public int numDupDigitsAtMostN(int n) {
        s = Integer.toString(n).toCharArray();
        int m = s.length;
        memo = new int[m][1<<10];
        for(int i=0;i<m;i++){
            Arrays.fill(memo[i],-1);
        }
        return n-f(0,0,true,false);
    }
    int f(int i,int mask,boolean isLimited,boolean isNum){
        if(i==s.length) return isNum?1:0;

        if (!isLimited && isNum && memo[i][mask]!= -1)
            return memo[i][mask];
        int res = 0;
        if(!isNum){
            //表示可以跳过位
            res = f(i+1,mask,false,false);
        }
        //不跳过
        int up = isLimited?s[i]-'0':9;
        for(int d=isNum?0:1;d<=up;d++){
            if((mask>>d &1)==0){
                res+=f(i+1,mask|(1<<d),isLimited&&d==up,true);
            }
        }
        if(!isLimited && isNum){
            memo[i][mask] = res;
        }
        return res;
    }
}

六、数字 1 的个数(力扣233)【数位DP】

在这里插入图片描述
分析
利用上一题模板 没有前导零不需要考虑isNum
只需要计算1出现的次数

class Solution {
    char[] s;
    int[][] dp;
    //mask:标志 此题中只需要找一 
    //isNum:需要注意前导零时,需要该标志位
    //isLimit:是否收到了限制
    public int countDigitOne(int n) {
        s = Integer.toString(n).toCharArray();
        var m = s.length;
        dp = new int[m][m];
        for(int i=0;i<m;i++){
            Arrays.fill(dp[i],-1);
        }
        return f(0,0,true);
    }
    int f(int i,int mask,boolean isLimit){
        if(i==s.length) return mask;
        //无限制条件下结束
        if(!isLimit && dp[i][mask]>=0) return dp[i][mask];
        int res =0;
        int up = isLimit?s[i]-'0':9;
        for(int d = 0;d<=up;d++){
            res+=f(i+1,mask+(d==1?1:0),isLimit&d==up);
        }
        if(!isLimit) dp[i][mask] = res;
        return res;
    }
}

七、2出现的次数(面试题 17.06)

在这里插入图片描述
分析:
与上一题一摸一样

class Solution {
    char[] s;
    int[][] dp;
    public int numberOf2sInRange(int n) {
        s = Integer.toString(n).toCharArray();
        int m = s.length;
        dp = new int[m][m];
        for(int i=0;i<m;i++){
            Arrays.fill(dp[i],-1);
        }
        return f(0,0,true);
    }
    int f(int i,int cnt,boolean isLimit){
        if(i==s.length) return cnt;
        if(!isLimit && dp[i][cnt]>=0) return dp[i][cnt];
        int res =0;
        int up = isLimit?s[i]-'0':9;
        for(int d=0;d<=up;d++){
            res += f(i+1,cnt+(d==2?1:0),isLimit&d==up);
        }
        if(!isLimit) dp[i][cnt] = res;
        return res;
    }
}

八、每日一题day72:无矛盾的最佳球队(力扣1626)【动态规划】

在这里插入图片描述
动规五部曲:
1、确定dp[]数组及下标含义

dp[i]:表示第i个(包含第i个)球员之前拿到的没有矛盾的最大分数

2、递推公式

dp[i] = Math.max(dp[i],dp[j])
//为了方便处理只有一个数据的情况
在循环外:
dp[i] += people[i][0];

3、初始化

dp[0] = people[0][0]

4、遍历顺序

从左到右

class Solution {
    public int bestTeamScore(int[] scores, int[] ages) {
        //动态规划
        int n = scores.length;
        int[][] people = new int[n][2];
        for(int i=0;i<n;i++){
            people[i][0] = scores[i];
            people[i][1] = ages[i];
        }
        int[] dp = new int[n];
        int res = 0;
        //按照分数递增排序 当分数相同时 按照年龄递增排序
        Arrays.sort(people,(a,b)->a[0]!=b[0]?a[0]-b[0]:a[1]-b[1]);
        for(int i=0;i<n;i++){
            for(int j=i-1;j>=0;j--){
                if(people[i][1]>=people[j][1]){
                    dp[i] = Math.max(dp[j],dp[i]);
                }
            }
            dp[i] +=people[i][0];
            res = Math.max(dp[i],res);
        }
        return res;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值