数据结构:Map & set - 习题(三)

一、只出现一次的数字

题目链接https://leetcode.cn/problems/single-number/description/

描述:

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

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

解析:我们创建一个set,如果set中没有这个元素我们就将这个元素放入set中,如果set中存在这个元素我们就将这个元素在set中移除。最后我们set中的元素就是只出现一次的元素,因此我们可以在遍历一遍数组查看是哪个元素。

java 复制代码
class Solution {
    public int singleNumber(int[] nums) {
       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;
    }
}

但是上述方法并不是最最快的解法,我们最快的解法是利用位运算的方式,我们利用异或的方式来解决:我们依次得到所有的元素进行异或,我们创建一个变量n=0,而0^1 = 1,当我们遇到相同的元素时 1^1 = 0,因此我们遇到没有重复的元素时,经过异或就能得到这个只出现一次的元素:1^1^2=2

java 复制代码
class Solution {
    public int singleNumber(int[] nums) {
        int n = 0;
        for(int num : nums){
            n^=num;
        }
        return n;
    }
}

二、随机链表的复制

习题链接https://leetcode.cn/problems/copy-list-with-random-pointer/description/

描述:

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

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

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

返回复制链表的头节点。

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

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

这道题,我们想要直接拷贝我们发现这其实时不可以,因为我们发现当我们拷贝完后发现,我们的next和random所指向的就不是我们拷贝完后的结点了。同时我们也可以发现我们的random的指向的下一个结点是跳跃的指向,自己本身或者指向的是空。

既让是这样,我们可以利用我们的Map,Map里存放的是<Node,Node>,我们根据我们的链表将拷贝后结点的val值存放到新的结点中,然后我们在根据我们拷贝到Map的结点值将对应的next和random拷贝到新的结点当中

java 复制代码
class Solution {
    public Node copyRandomList(Node head) {
        Map<Node,Node> map = new HashMap<>();
        Node cur = head;
        while(cur != null){
            Node node = new Node(cur.val);
            map.put(cur,node);
            cur = cur.next;
        }
        cur = head;
        while(cur != null){
            map.get(cur).next = map.get(cur.next);
            map.get(cur).random = map.get(cur.random);
            cur = cur.next;
        }
        return map.get(head);
    }
}

三、宝石与石头

习题链接https://leetcode.cn/problems/jewels-and-stones/description/

描述:

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

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

解析:我们可以利用set,把宝石中的每个字符放到set中,然后遍历石头的所有字符,每遍历一个字符就到set中查看是否存在,如果存在就让count++;

java 复制代码
class Solution {
    public int numJewelsInStones(String jewels, String stones) {
        Set<Character> set = new HashSet<>();
        for(int i = 0;i < jewels.length();i++){
            char ch = jewels.charAt(i);
            set.add(ch);
        }
        int count = 0;
        for(int i = 0;i < stones.length();i++){
            char ch = stones.charAt(i);
            if(set.contains(ch)){
                count++;
            }
        }
        return count;
    }
}

四、旧键盘

习题链接https://www.nowcoder.com/questionTerminal/f88dafac00c8431fa363cd85a37c2d5e

描述:

旧键盘上坏了几个键,于是在敲一段文字的时候,对应的字符就不会出现。现在给出应该输入的一段文字、以及实际被输入的文字,请你列出
肯定坏掉的那些键。

复制代码

解析:我们知道Set是天然去重的因此我们可以将错误键盘打印出来的结果放到set1中,这样set1中的结果就是我们好的键,之后我们在遍历我们原本要打印的结果,如果set1中不存在并且set2中不存在就将这个字符打印并存入set2中

java 复制代码
import java.util.*;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
        while (in.hasNextLine()) { // 注意 while 处理多个 case
            String str1 = in.nextLine();
            String str2 = in.nextLine();
            fun(str1,str2);
        }
    }

    public static void fun(String str1,String str2){
        Set<Character> set1 = new HashSet<>();
        for(char ch : str2.toUpperCase().toCharArray()){
            set1.add(ch);
        }
        Set<Character> set2 = new HashSet<>();
        for(char ch : str1.toUpperCase().toCharArray()){
            if(!set1.contains(ch) && !set2.contains(ch)){
                System.out.print(ch);
                set2.add(ch);
            }
        }

    }
}

好了,今天的讲解就到这里了,还请大家多多关注,我们下一篇见!

相关推荐
%d%d26 分钟前
找不到依赖项 <…> (Maven)
java·ide·intellij-idea
五味香11 分钟前
C语言学习,希尔排序
android·c语言·开发语言·数据结构·学习·算法·排序算法
无际单片机编程30 分钟前
单片机延时函数怎么写规范?
java·c语言·stm32·单片机·嵌入式硬件
念言-ny1 小时前
sentinel小记
java·spring boot·sentinel
Hamm1 小时前
封装一个优雅的自定义的字典验证器,让API字典参数验证更湿滑
java·spring boot·后端
逆鱼_041 小时前
Unix-进程和线程
java·服务器·unix
总是学不会.1 小时前
EasyExcel 实践案例:打印工资条
java·开发
m0_748250741 小时前
Spring Boot 多数据源解决方案:dynamic-datasource-spring-boot-starter 的奥秘(上)
java·spring boot·后端
波音彬要多做2 小时前
49 set与map的模拟实现
开发语言·数据结构·c++·学习·算法
quo-te2 小时前
【JavaWeb学习Day19】
java·spring·maven·mybatis