刷题(新手村6题)

第一题:

1480.一维数组的动态和(简单)
给你一个数组 nums 。数组「动态和」的计算公式为:runningSum[i] = sum(nums[0]…nums[i]) 。请返回 nums 的动态和。
示例 1:
输入:nums = [1,2,3,4]
输出:[1,3,6,10]
解释:动态和计算过程为 [1, 1+2, 1+2+3, 1+2+3+4] 。

示例 2:
输入:nums = [1,1,1,1,1]
输出:[1,2,3,4,5]
解释:动态和计算过程为 [1, 1+1, 1+1+1, 1+1+1+1, 1+1+1+1+1] 。

示例 3:
输入:nums = [3,1,2,10,1]
输出:[3,4,6,16,17]

提示:
1 <= nums.length <= 1000
-10^6 <= nums[i] <= 10^6

解决:

class Solution {
    public int[] runningSum(int[] nums) {
        int sums[]=new int [nums.length];
        sums[0] = nums[0];
        for(int i=0;i<nums.length-1;i++){
            int sum=sums[i]+nums[i+1];
            sums[i+1]=sum;
        }
        return sums;
    }
}

出错处及原因:

  1. 数组索引越界: i<nums.length-1;int sum=sums[i]+nums[i+1];
  2. 声明数组但未初始化(即分配空间):int sums[]=new int [nums.length];
    当声明数组但未分配空间时:int sums[ ] = null;
    (数组类型属于引用类型,赋值为null表时可指向任何内存空间,避免引用数组时出现异常)

官方题解:

class Solution {
    public int[] runningSum(int[] nums) {
        int n = nums.length;
        for (int i = 1; i < n; i++) {
            nums[i] += nums[i - 1];
        }
        return nums;
    }
}

在这里插入图片描述

第二题:

1342.将数字变成 0 的操作次数(简单)
给你一个非负整数 num ,请你返回将它变成 0 所需要的步数。 如果当前数字是偶数,你需要把它除以 2 ;否则,减去 1 。

示例 1:
输入:num = 14
输出:6
解释:
步骤 1) 14 是偶数,除以 2 得到 7 。
步骤 2) 7 是奇数,减 1 得到 6 。
步骤 3) 6 是偶数,除以 2 得到 3 。
步骤 4) 3 是奇数,减 1 得到 2 。
步骤 5) 2 是偶数,除以 2 得到 1 。
步骤 6) 1 是奇数,减 1 得到 0 。

示例 2:
输入:num = 8
输出:4
解释:
步骤 1) 8 是偶数,除以 2 得到 4 。
步骤 2) 4 是偶数,除以 2 得到 2 。
步骤 3) 2 是偶数,除以 2 得到 1 。
步骤 4) 1 是奇数,减 1 得到 0 。

示例 3:
输入:num = 123
输出:12

提示:
0 <= num <= 10^6

解决:

class Solution {
    public int numberOfSteps(int num) {
        int sum =0;
        while(num !=0){
            if(num%2 ==0){
                num=num/2;
                sum+=1;
            }else{
                num=num-1;
                sum+=1;
            }
        }
        return sum;
    }
}

官方题解:

在这里插入图片描述

class Solution {
    public int numberOfSteps(int num) {
        int ret = 0;
        while (num > 0) {
            ret += (num > 1 ? 1 : 0) + (num & 0x01);
            num >>= 1;
        }
        return ret;
    }
}

使用方法:

  1. java中有三种移位运算符:<< :左移运算符,num << 1,相当于num乘以2;
    >> :右移运算符,num >> 1,相当于num除以2;
    >>> : 无符号右移,忽略符号位,空位都以0补齐;
    num >>= 1 就是 num = num >> 1;
    其中 >> 是右移运算符,表示将一个数的二进制值向右移动指定的位数;
    如果传入参数是14,14的二进制1110,右移一位就是111,111十进制是7;那么 14 >> 1 就是 7;
  2. 三元运算符:变量=(条件)?expression1:expression2
    如果条件返回true,则执行expression1,否则执行expression2,并将最终结果存储在变量中。
  3. num & 0x01 //通过if(num & 1)可判断num奇偶性
    0x01是16进制,代表1的意思,那么就是num & 1;
    &是位运算,同位与,意思是转成二进制,之后,相同位置都是1才是1,否则都是0;
    0000001 跟 1111111,结果就是1;
    0000001 跟 11111111111110,结果就是0;
    那么传入参数14,14 & 1,14的二进制1110,1110 & 1 结果就是0;

奇数 +/- 1 = 偶数
每次循环直接除以2
若num为奇数且不为1则增加两次操作次数(相当于先num–再num/=2)
若num为偶数有(num > 1 ? 1 : 0)==1且(num & 0x01)==0则增加一次操作次数
若num为奇数且为1则增加一次操作次数(num–后归零不再操作)
参考链接
参考链接

第三题:

1672.最富有客户的资产总量(简单)
给你一个 m x n 的整数网格 accounts ,其中 accounts[i][j] 是第 i​​​​​​​​​​​​ 位客户在第 j 家银行托管的资产数量。返回最富有客户所拥有的资产总量 。客户的资产总量就是他们在各家银行托管的资产数量之和。最富有客户就是资产总量最大的客户。

示例 1:
输入:accounts = [[1,2,3],[3,2,1]]
输出:6
解释:
第 1 位客户的资产总量 = 1 + 2 + 3 = 6
第 2 位客户的资产总量 = 3 + 2 + 1 = 6
两位客户都是最富有的,资产总量都是 6 ,所以返回 6 。

示例 2:
输入:accounts = [[1,5],[7,3],[3,5]]
输出:10
解释:
第 1 位客户的资产总量 = 6
第 2 位客户的资产总量 = 10
第 3 位客户的资产总量 = 8
第 2 位客户是最富有的,资产总量是 10

示例 3:
输入:accounts = [[2,8,7],[7,1,3],[1,9,5]]
输出:17

提示:
m == accounts.length
n == accounts[i].length
1 <= m, n <= 50
1 <= accounts[i][j] <= 100

解决:

class Solution {
    public int maximumWealth(int[][] accounts) {
        int sums[]=new int[accounts.length];
        for(int i =0;i<accounts.length;i++){
            int sum = 0;
            for(int j=0;j<accounts[i].length;j++){
                sum+=accounts[i][j];    
            }
            sums[i]=sum;
        }
        int max=sums[0];
        for(int i=0;i<sums.length-1;i++){
            if(max<sums[i+1]){
                max=sums[i+1];
            }
        }
        return max;
    }
}

官方题解:

class Solution {
    public int maximumWealth(int[][] accounts) {
        int maxWealth = Integer.MIN_VALUE;
        for (int[] account : accounts) {
            maxWealth = Math.max(maxWealth, Arrays.stream(account).sum());
        }
        return maxWealth;
    }
}

使用方法:

  1. Integer.MAX_VALUE表示int数据类型的最大取值数:2147483647
    Integer.MIN_VALUE表示int数据类型的最小取值数:-2147483648
  2. 遍历集合
String[] abc = new String[3]{“a”,“b”,“c”};
forString str : abc){
System.out.println(str); //这个地方的冒号就是遍历abc的集合,取出每一个元素
  1. Math.max() 方法用于返回两个参数中的最大值
  2. 使用stream流
    int total=Arrays.stream(nums).sum(); 可以求得nums[]所有元素和
    求数组中的最大值::将nums数组转化为stream流然后得到流中的最大值,最后再以int类型获取
    int max = Arrays.stream(nums).max().getAsInt();
    求数组中的最小值:将nums数组转化为stream流然后得到流中的最小值,最后再以int类型获取
    int min = Arrays.stream(nums).min().getAsInt();

1万以内的数据,for循环的性能要高于foreach和stream;
数据量上去之后,基本没有什么差距,但是Stream提供并行处理,在数据量大了之后,效率会明显增强。(但是单核CPU,Stream并行处理可能会效率更慢

参考链接
参考链接

第四题:

412.Fizz Buzz
给你一个整数 n ,找出从 1 到 n 各个整数的 Fizz Buzz 表示,并用字符串数组 answer(下标从 1 开始)返回结果,其中:
answer[i] == “FizzBuzz” 如果 i 同时是 3 和 5 的倍数。
answer[i] == “Fizz” 如果 i 是 3 的倍数。
answer[i] == “Buzz” 如果 i 是 5 的倍数。
answer[i] == i (以字符串形式)如果上述条件全不满足。

示例 1:
输入:n = 3
输出:[“1”,“2”,“Fizz”]

示例 2:
输入:n = 5
输出:[“1”,“2”,“Fizz”,“4”,“Buzz”]

示例 3:
输入:n = 15
输出:[“1”,“2”,“Fizz”,“4”,“Buzz”,“Fizz”,“7”,“8”,“Fizz”,“Buzz”,“11”,“Fizz”,“13”,“14”,“FizzBuzz”]

提示:1 <= n <= 104

解决:

class Solution {
    public List<String> fizzBuzz(int n) {
        List<String> res = new ArrayList<>(n);
        String three = "Fizz";
        String five = "Buzz";
        String threeFive = "FizzBuzz";

        for(int i=1;i<n+1;i++){
            if(i%3==0 && i%5==0){
                res.add(threeFive);
            }else if(i%3==0 && i%5!=0){
                res.add(three);
            }else if(i%3!=0 && i%5==0){
                res.add(five);
            }else{
                res.add(""+i);
            }
        }
        return res;
    }
}

官方题解:

在这里插入图片描述

class Solution {
    public List<String> fizzBuzz(int n) {
        List<String> answer = new ArrayList<String>();
        for (int i = 1; i <= n; i++) {
            StringBuffer sb = new StringBuffer();
            if (i % 3 == 0) {
                sb.append("Fizz");
            }
            if (i % 5 == 0) {
                sb.append("Buzz");
            }
            if (sb.length() == 0) {
                sb.append(i);
            }
            answer.add(sb.toString());
        }
        return answer;
    }
}

使用方法:

  1. Integer.MAX_VALUE表示int数据类型的最大取值数:2147483647
    Integer.MIN_VALUE表示int数据类型的最小取值数:-2147483648
    参考链接

第五题:

383.赎金信
给你两个字符串:ransomNote 和 magazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。如果可以,返回 true ;否则返回 false 。magazine 中的每个字符只能在 ransomNote 中使用一次。

示例 1:
输入:ransomNote = “a”, magazine = “b”
输出:false

示例 2:
输入:ransomNote = “aa”, magazine = “ab”
输出:false

示例 3:
输入:ransomNote = “aa”, magazine = “aab”
输出:true

提示:
1 <= ransomNote.length, magazine.length <= 105
ransomNote 和 magazine 由小写英文字母组成

解决:
方法一:(有问题,示例三return false;)

class Solution {
    public boolean canConstruct(String ransomNote, String magazine) {
        String[] m=magazine.split("");
        String[] r=ransomNote.split("");

        int sum=0;
        for(int i=0;i<m.length;i++){
            for(int j=0;j<r.length;j++){
                if(m[i] == r[j]){
                    sum+=1;
                    m[i]=("0");
                    r[j]=("0"); 
                }
            }
        }
        int len=r.length;
        if(sum==len){
            return true;
        }else{
            return false;
        }
    }
}

方法二:暴力求解

class Solution {
    public boolean canConstruct(String ransomNote, String magazine) {
        char[] m=magazine.toCharArray();
        char[] r=ransomNote.toCharArray();

        for(int i=0;i<r.length;i++){
            for(int j=0;j<m.length;j++){
                if(r[i] == m[j]){
                    r[i]='0';
                    m[j]='0'; 
                    continue;
                }
            }
        }
        for(int i=0;i<r.length;i++){
            if(r[i] != '0'){
                return false;
            }
        }
        return true;
    }
}

题解:

使用哈希表

class Solution {
    public boolean canConstruct(String ransomNote, String magazine) {
        char[] str1 = ransomNote.toCharArray();// toCharArray()将字符串转换为字符数组
        char[] str2 = magazine.toCharArray();
        
        Map<Character,Integer> map = new HashMap<Character,Integer>(); //创建Map集合对象
        //遍历str1数组的每一个元素,存入哈希表中。
        for(char z : str1){//把ransomNote的值存进哈希表,如果存在相同,则value +1
            if(map.containsKey(z)){
                map.put(z,map.get(z) + 1);
            }else{
                map.put(z,1);
            }
        }
        for(char z : str2){//通过遍历magazine字符来抵消ransomNote字符
            if(map.containsKey(z)){
                map.put(z,map.get(z) - 1);                
            }
        }
        for(char z : str1){//因为ransomNote与哈希表key相似,所以通过ransomNote遍历hashmap
            int index = map.get(z);
            if(index > 0){//如果index存在大于0的,说明magazine未能完全抵消ransomNote,即不能由他里面的字符构成
                return false;
            }
        }
        return true;
    }
}

使用方法:

  1. toCharArray() 与 split()
    String.toCharArray 方法,作用:将字符串转换为字符数组。
    Split函数是编程语言中使用的函数,是指返回一个下标从零开始的一维数组,它包含指定数目的子字符串。
    Split和ToCharArray的区别:
    (1)split是根据你需要按照的分隔符来分割的,比如:String a = “avc,d,e,s,f”; String []b = a.split(‘,’);这个就是根据逗号将数据分开,遍历输出得到的b的对象为"avc",“d”,“e”,“s”,“f”。
    (2)toCharArray是将String对象的每一个下标位的对象保存在char[]中,比如:String a = “abcd”; char[] b = a.toCharArray(); 这个b保存的信息就是[‘a’,‘b’,‘c’,‘d’]。
  2. Map集合
    1.public V put (K key,V value) 把指定的键和值添加到Map集合中,返回值是V
    如果要存储的键值对,key不重复返回值V是null
    如果要存储的键值对,key重复返回值V是被替换的value值
    2.public V remove(Object key把指定键所对应的键值对元素,在Map集合中删除,返回被删除的元素的值。 返回值:
    V 。如果key存在,返回被删除的值,如果key不存在,返回null
    3.public V get (Object key):根据指定的键 在Map集合中获取对应的值.如果key存在,
    返回对应的value值,如果key不存在,返回null
    4.boolean containsKey( Object key)判判断集合中是否包含指定的键
    5.遍历Map集合
    5.1.通过键找值的方法;使用了setKey方法,将Map集合中的key值,存储到Set集合,用迭代器或foreach循环遍历Set集
    合来获取Map集合的每一个key,并使用get(key)方法来获取value值
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    5.2.使用Entry对象遍历

Map.Entry<K,V>,在Map接口中有一个内部接口Entry(内部类)

作用:当集合一创建,就会在Map集合中创建一个Entry对象,用来记录键与值(键值对对象,键值的映射关系)
在这里插入图片描述
有了Entry对象就可以使用Map中的entrySet方法,把Map集合中的多个Entry对象存入一个Set集合来遍历Set集合,获取Set集合中每一个Entry对象,然后可以使用Entry中的两个方法getKey和getValue来分别获取键和值。
代码步骤:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
6.Map的常用实现类
(一)、HashMap
【1】.特点:1.HashMap底是哈希表,查询速度非常快(jdk1.8之前是数组+单向链表,1.8之后是数组+单向链表/红黑树 ,链
表长度超过8时,换成红黑树)
2. HashMap是无序的集合,存储元素和取出元素的顺序有可能不一致
3.集合是不同步的,也就是说是多线程的,速度快
【2】.HashMap存储自定义类型键值
HashMap存储自定义类型键值,Map集合保证key是唯一的:作为key的元素,必须重写hashCode方法和equals方法,以保证key唯一

在这里插入图片描述
在这里插入图片描述

(二)LinkedHashMap
HashMap有子类LinkedHashMap:LinkedHashMap <K,V> extends HashMap <K,V>
是Map接口的哈希表和链表的实现,具有可预知的迭代顺序(有序)
底层原理:哈希表+链表(记录元素顺序)
特点:1.LinkedHashMap底层是哈希表+链表(保证迭代的顺序)
2.LinkedHashMap是一个有序的集合,存储元素和取出元素的顺序一致
改进之处就是:元素存储有序了

(三)Hashtable
Hashtable<K,V> implements Map<K,V>
Hashtable:底层也是哈希表,是同步的,是一个单线程结合,是线程安全的集合,速度慢
HashMap:底层也是哈希表,但是线程不安全的集合,是多线程集合,速度快
HashMap(还有之前学的所有集合):都可以存储null键,null值
Hashtable:不能存储null键,null值
在这里插入图片描述
包含返回true,不包含返回false
参考链接

第六题:

876.链表的中间结点(简单)
给你单链表的头结点 head ,请你找出并返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。

示例 1:
输入:head = [1,2,3,4,5]
输出:[3,4,5]
解释:链表只有一个中间结点,值为 3 。

示例 2:
输入:head = [1,2,3,4,5,6]
输出:[4,5,6]
解释:该链表有两个中间结点,值分别为 3 和 4 ,返回第二个结点。

提示:
链表的结点数范围是 [1, 100]
1 <= Node.val <= 100

解决:

class Solution {
    public ListNode middleNode(ListNode head) {
        ListNode[] A = new ListNode[100];
        int t = 0;
        while (head != null) {
            A[t++] = head;
            head = head.next;
        }
        return A[t / 2];
    }
}

官方题解:

方法一:我们可以考虑对链表进行遍历,同时将遍历到的元素依次放入数组 A 中。如果我们遍历到了 N 个元素,那么链表以及数组的长度也为 N,对应的中间节点即为 A[N/2]。

class Solution {
    public ListNode middleNode(ListNode head) {
        ListNode[] A = new ListNode[100];
        int t = 0;
        while (head != null) {
            A[t++] = head;
            head = head.next;
        }
        return A[t / 2];
    }
}

方法二:单指针法
我们可以对方法一进行空间优化,省去数组 A。
我们可以对链表进行两次遍历。第一次遍历时,我们统计链表中的元素个数 N;第二次遍历时,我们遍历到第 N/2 个元素(链表的首节点为第 0 个元素)时,将该元素返回即可。

class Solution {
    public ListNode middleNode(ListNode head) {
        int n = 0;
        ListNode cur = head;
        while (cur != null) {
            ++n;
            cur = cur.next;
        }
        int k = 0;
        cur = head;
        while (k < n / 2) {
            ++k;
            cur = cur.next;
        }
        return cur;
    }
}

方法三:快慢指针法
我们可以继续优化方法二,用两个指针 slow 与 fast 一起遍历链表。slow 一次走一步,fast 一次走两步。那么当 fast 到达链表的末尾时,slow 必然位于中间。

class Solution {
    public ListNode middleNode(ListNode head) {
        ListNode slow = head, fast = head;
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
        }
        return slow;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值