J20250708 算法题5道

题目一览:

888. 公平的糖果交换 - 力扣(LeetCode)(hashmap 简单

2. 两数相加 - 力扣(LeetCode)中等

136. 只出现一次的数字 - 力扣(LeetCode)(hashset 简单

138. 随机链表的复制 - 力扣(LeetCode)(hashmap 中等

771. 宝石与石头 - 力扣(LeetCode)(hashset 简单

7.07~7.11的五道题目,几乎是简单题,重心暂时不放在算法练习上。

题解:

888.公平的糖果交换

爱丽丝和鲍勃拥有不同总数量的糖果。给你两个数组 aliceSizes 和 bobSizes ,aliceSizes[i] 是爱丽丝拥有的第 i 盒糖果中的糖果数量,bobSizes[j] 是鲍勃拥有的第 j 盒糖果中的糖果数量。

两人想要互相交换一盒糖果,这样在交换之后,他们就可以拥有相同总数量的糖果。一个人拥有的糖果总数量是他们每盒糖果数量的总和。

返回一个整数数组 answer,其中 answer[0] 是爱丽丝必须交换的糖果盒中的糖果的数目,answer[1] 是鲍勃必须交换的糖果盒中的糖果的数目。如果存在多个答案,你可以返回其中 任何一个 。题目测试用例保证存在与输入对应的答案。

解:这题我采用的是哈希表,关键是---->如何才能在两个数组中找到正确的要交换的两个数。

1)可以根据方程计算:设Alice交换的糖果数为x,bob交换的糖果数为y,因为在交换后两个人的糖果数量相同,所以aliceSizes - x + y = bobSizes - y + x,将这个方程进行调整,可以得到(aliceSizes - bobSizes) / 2 + y = x

2)我们将aliceSizes数组的每个值 以及 对应的下标 作为哈希表的键对值,这样在后续的的查找中,我们可以去遍历bobSizes数组。

3)将((aliceSizes - bobSizes) ) / 2 + bobSizes[ i ] 传给map.get,看map中是否能找到对应的value,找到的值即为alice要交换的那盒糖的下标 j ,将bobSizes[ i ] 和 aliceSizes[ j ] 给answer数组返回即可

代码:

class Solution {
    public int[] fairCandySwap(int[] aliceSizes, int[] bobSizes) {
        //哪两个数可以交换的方法思想
        Map<Integer,Integer> hashmap = new HashMap<>();
        int numA = 0;
        int numB = 0;

        for(int i = 0;i < aliceSizes.length;i++){
            hashmap.put(aliceSizes[i],i);
            numA = numA + aliceSizes[i];
        }
        for(int i = 0;i < bobSizes.length;i++){
            numB = numB + bobSizes[i];
        }

        int ret = (numA - numB)/2;
        int[] answer = new int[2];
        for(int j = 0;j<bobSizes.length;j++){
            Integer key = hashmap.get(ret+bobSizes[j]);
            if(key != null){
                answer[0] = aliceSizes[key];
                answer[1] = bobSizes[j];
                break;
            } 
        }
        return answer;
    }
}

2.两数相加

给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。

解:这道题可以用简单的数学计算去思考。

1) 两个链表的指针从头开始同时向后移动,例如链表A:2->4->3,链表B:5->6->4,将2和4相加后,链表同步向后,分别指向4和6。

2 )根据朴素的数学计算,我们知道十进制是 十进一,所以我们需要一个变量carry 去记录进位的数,然后加到下一次的计算中

3)如果一个链表先为空,而另一个链表不为空,则将下一次相加的数设置为0,直到两个链表为空,计算完毕。

4)需要注意的是,最后循环结束,判断carry是否大于0 ,如果大于0 ,则代表还需要进位,在新链表的表尾插入一个节点即可。

代码:

/**
 * 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 addTwoNumbers(ListNode l1, ListNode l2) {
        //1.需要一个新的链表
        //2.用carry记录进位数
        ListNode head = null;
        ListNode tail = null;
        int carry = 0;//进位数
        while(l1 != null || l2 != null){
            int n1 = l1 != null ? l1.val : 0;
            int n2 = l2 != null ? l2.val : 0;
            //按照初等数学算数
            int res = (n1 + n2 + carry) % 10;
            carry = (n1 + n2 + carry) / 10;

            if(head == null){
                head = tail = new ListNode(res);
            }else{
                tail.next = new ListNode(res);
                tail = tail.next;
            }
            //移动指针 两个链表同时往后移 找到下一个对应的数
            if(l1 != null){
                l1 = l1.next;
            }
            if(l2 != null){
                l2 = l2.next;
            }
            
        }
        if(carry > 0){
            tail.next = new ListNode(carry);
            tail = tail.next;
        }
        return head;
    }
}

136. 只出现一次的数字

给你一个 非空 整数数组 nums ,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

你必须设计并实现线性时间复杂度的算法来解决此问题,且该算法只使用常量额外空间。

解:这道题可以用异或,通过位运算得到结果。但是因为我最近在学map和set,这里采用set的方法。

1)利用for循环遍历数组nums,set.contains(nums[ i ])检查set中是否已经存在nums[ i ] 。不存在则添加进set,存在则利用set.remove(nums[ i ])去重,循环结束后 在set中只留下一个数,就是正确结果。

2)因为最后返回类型为int,我们需要将set中的数返回,所以再次用一个for循环,找到set中留下的数是谁,并将其返回

代码:

class Solution {
    public int singleNumber(int[] nums) {
        //采用set
        Set<Integer> set = new HashSet();
        for(int i  = 0;i < nums.length;i++){
            if(!set.contains(nums[i])){
                set.add(nums[i]);
            }else{
                set.remove(nums[i]);
            }
        }
         for(int i  = 0;i < nums.length;i++){
            if(set.contains(nums[i])){
                return nums[i];
            }     
        }
        return -1;
    }
}

138. 随机链表的复制

给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。

构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 

例如,如果原链表中有 X 和 Y 两个节点,其中 X.random --> Y 。那么在复制链表中对应的两个节点 x 和 y ,同样有 x.random --> y 。

返回复制链表的头节点。

用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:

  • val:一个表示 Node.val 的整数。
  • random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为  null 。

你的代码  接受原链表的头节点 head 作为传入参数。

解:这道题目的要解决 首先要弄清楚题意 (画图解释)

怎样把原链表中节点的关系 复制到 新链表中?这里采用hashmap

我们将原链表和新链表放入map中,使二者拥有映射关系,这样就可以将关系复制。

map.put(cur,node),其中cur是原链表节点,node是新链表节点

这样我们利用map.get()时,就可以将原节点放入,从而找到新节点,使新节点之间按照原链表的连接方式连接起来,构造新链表

代码:

/*
// 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. 先创建对应数量的节点 将val一一传入
//2. 将老链表和新链表建立映射关系 利用hashmap
//3. 
class Solution {
    public Node copyRandomList(Node head) {

        Node cur = head;
        Map<Node,Node> map = new HashMap<>();
        //将新节点都创建完毕
        while(cur != null){
            Node node = new Node(cur.val);

            // 老表 新表 建立映射关系
            map.put(cur,node);
            cur = cur.next;
        }
        
        Node temp = head;
        while(temp != null){
            //将新表的各节点连接 
            map.get(temp).next = map.get(temp.next);
            //random也要对应
            map.get(temp).random = map.get(temp.random);
            temp = temp.next;

        }

        return map.get(head);
    }
}

771. 宝石与石头

给你一个字符串 jewels 代表石头中宝石的类型,另有一个字符串 stones 代表你拥有的石头。 stones 中每个字符代表了一种你拥有的石头的类型,你想知道你拥有的石头中有多少是宝石。

字母区分大小写,因此 "a" 和 "A" 是不同类型的石头。

解:这里我们首先想到的是,石头中的元素一一和宝石中的元素作对比,看是否为宝石。而为了实现这个想法,并且尽量去降低时间复杂度,使用HashSet

1)将String类型的宝石中的元素利用charAt()方法  一个个放进HashSet中

2)再去遍历石头,利用charAt()将石头中的字符与集合中的元素对照(利用contains()方法判断)

代码:

class Solution {
    //1.将string类型改为char[] 类型
    //2.将jewels放入集合中
    //3.遍历石头数组 看是否存在宝石
    public int numJewelsInStones(String jewels, String stones) {
        Set<Character> arr = new HashSet<>();
        for(int i = 0 ; i < jewels.length();i++){
            arr.add(jewels.charAt(i));
        }
        int count = 0;
        for(int i = 0; i < stones.length();i++){
            if(arr.contains(stones.charAt(i))){
                count++;
            }
        }
        return count;
    }
}

okk

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值