剑指Offer(第二版): 35. 复杂链表的复制 47. 礼物的最大价值 56 - II. 数组中数字出现的次数 II 16. 数值的整数次方

这篇博客介绍了两种不同的链表克隆方法,一种是哈希表思想,通过创建映射实现原链表到克隆链表的复制;另一种是原地修改链表,将拷贝节点插入原链表中,然后分离得到克隆链表。此外,还讨论了动态规划解决矩阵最大值问题的方法。解题思路清晰,代码实现详尽。
摘要由CSDN通过智能技术生成

在这里插入图片描述

/*
// Definition for a Node.
class Node {
    int val;
    Node next;
    Node random;

    public Node(int val) {
        this.val = val;
        this.next = null;
        this.random = null;
    }
}
*/
/**
解题思想1:哈希表思想,用哈希表来存储一个映射,原节点----->拷贝节点
 */
class Solution {
    public Node copyRandomList(Node head) {
        if(head == null)
            return null;
        //map中存的是(原节点,拷贝节点)的一个映射
        Map<Node,Node> map = new HashMap<>();
        Node tmp = head;
        while(tmp!=null){
            map.put(tmp,new Node(tmp.val));
            tmp = tmp.next;
        } 
        //将拷贝的节点组织成一个链表,和random没关系
        Node tmp1 = head;
        while(tmp1!=null){
            map.get(tmp1).next = map.get(tmp1.next);
            map.get(tmp1).random = map.get(tmp1.random);
            tmp1 = tmp1.next;
        } 
        return map.get(head);
    }
}

/**
解题思路2:①、将拷贝节点放到原节点后面  ②、把拷贝的节点random指针安排上  ③、分离拷贝节点和原节点
 */
class Solution {
    public Node copyRandomList(Node head) {
        if(head == null)
            return head;
        //将拷贝节点放到原节点后面,例如1->2->3这样的链表就变成了这样1->1'->2->2'->3->3'
        for(Node node = head , copy = null ; node!=null ; node = node.next.next){
            copy = new Node(node.val);
            copy.next = node.next;
            node.next = copy;
        }
        //把拷贝节点的random指针安排上
        for(Node node = head ; node!=null ; node = node.next.next){
            if(node.random!=null)
                node.next.random = node.random.next;
        }
        //分离拷贝节点和原节点,变成1->2->3和1'->2'->3'两个链表,后者就是答
        Node newHead = head.next;
        for(Node node = head , tmp = null ; node!=null&& node.next!=null;){
            tmp = node.next;
            node.next = tmp.next;
            node = tmp;
        }
        return newHead;
    }
}

在这里插入图片描述

/**
解题思路:动态规划
 */
class Solution {
    public int maxValue(int[][] grid) {
        int lenR = grid.length;
        if(lenR == 0)
            return 0;
        int lenC = grid[0].length;
        int[][] dp = new int[lenR][lenC];
        dp[0][0] = grid[0][0];
        for(int i=1 ; i<lenR ; i++){
            dp[i][0] = dp[i-1][0]+grid[i][0];
        }
        for(int j=1 ; j<lenC ; j++){
            dp[0][j] = dp[0][j-1] + grid[0][j];
        }
        //遍历数组
        for(int i=1 ; i<lenR ; i++){
            for(int j=1 ; j<lenC; j++){
                dp[i][j] = Math.max(dp[i-1][j],dp[i][j-1]) + grid[i][j];
            }
        }
        return dp[lenR-1][lenC-1];
    }
}

在这里插入图片描述

/**
解题思路:目前没有想到好的方法:就想到利用哈希表存值
 */
class Solution {
    public int singleNumber(int[] nums) {
        Map<Integer , Integer> map = new HashMap<>();
        for(int num : nums){
            if(map.containsKey(num))
                map.put(num , map.get(num)+1);      //比getOrDefault好用
            else
                map.put(num , 1);
        }
        for(int num : nums){
            if(map.get(num) == 1)
                return num;
        }
        return -1;
    }
}

/**
书上解法: 如果一个数字出现3次,它的二进制每一位也出现的3次。如果把所有的出现三次的数字的二进制表示的每一位都分别加起来,那么每一位都能被3整除。 我们把数组中所有的数字的二进制表示的每一位都加起来。如果某一位能被3整除,那么这一位对只出现一次的那个数的这一肯定为0。如果某一位不能被3整除,那么只出现一次的那个数字的该位置一定为1.
 */
class Solution {
    public int singleNumber(int[] nums) {
        int[] k = new int[32];
        for(int num : nums){
            for(int i=0 ; i<32; i++){
                k[i]+=num&1;
                num>>=1;
            }
        }
        int res = 0;
        for(int i=0 ; i<32; i++){
            res |= (k[i]%3)<<i;
        }
        return res;
    }
}

class Solution {
    public double myPow(double x, int n) {
        if(n==0)
            return 1;
        if(n==1)
            return x;
        if(n==-1)
            return 1/x;
        double div = myPow(x,n/2);
        double mod = myPow(x,n%2);
        return div*div*mod;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值