首页 > 编程语言 >java数据结构与算法刷题-----LeetCode1005. K 次取反后最大化的数组和(这就不是简单题)

java数据结构与算法刷题-----LeetCode1005. K 次取反后最大化的数组和(这就不是简单题)

时间:2024-03-19 16:00:49浏览次数:25  
标签:LeetCode1005 hash int sum 取反 负数 java 100 取负

java数据结构与算法刷题目录(剑指Offer、LeetCode、ACM)-----主目录-----持续更新(进不去说明我没写完):https://blog.csdn.net/grd_java/article/details/123063846

卷来卷去,把简单题都卷成中等题了

文章目录

在这里插入图片描述

1. 排序后从小到大取负

解题思路:时间复杂度O( n ∗ l o g 2 n n*log_{2}n n∗log2​n),时间复杂度的大头就是排序算法. 空间复杂度O( l o g 2 n log_{2}n log2​n),快速排序算法需要栈空间

将数组排序后,从小到大取负即可

代码

在这里插入图片描述

class Solution {
    public int largestSumAfterKNegations(int[] nums, int k) {
        // 排序,把可能有的负数排到前面
        Arrays.sort(nums);
        int sum = 0;
        for (int i = 0; i < nums.length; i++) {
            // 贪心:如果是负数,而k还有盈余,就把负数反过来
            if (nums[i] < 0 && k > 0) {
                nums[i] = -1 * nums[i];
                k--;
            }
            sum += nums[i];
        }
        Arrays.sort(nums);
        // 如果k没剩,那说明能转的负数都转正了,已经是最大和,返回sum
        // 如果k有剩,说明负数已经全部转正,所以如果k还剩偶数个就自己抵消掉,不用删减,如果k还剩奇数个就减掉2倍最小正数。
        return sum - (k % 2 == 0 ? 0 : 2 * nums[0]); 
    }
}

2. hash表从小到大排序,省掉排序(这就是为什么这题不是简单题)

上面方法一,排序浪费了大量时间,这个方法,将排序的时间省下来了 , 一举将这道简单题,升为中等难度的题。

解题思路:时间复杂度O( n + c n+c n+c),n是数组长度,c是数组中元素的取值范围. 空间复杂度O( C C C)
  1. 先将数组所有数字放入hash表统计其在数组中出现的次数,并且统计数组的所有元素和sum
  2. 然后从小到大依次对hash表中的负数取负(因为是负数,越小,取负后就越大。比如-100 和0 ,明显-100更小,但是取负后,变为100和0,100反而更大)
  3. 共取负k次,取负的过程中,修改sum的值,如何修改呢?这个是个固定套路。

将sum中的某一个负数(-x)改为正数(x),需要加两倍的x. 例如5 + (-1) = 4 , -1取负后结果为 5 + 1 = 6; ==> 4 + 1*2 = 6。也就是sum + (-x) = newSum, 取负 newSum + 2 * x = newNewSum

  1. 此时如果所有负数都取负完成,k依然没有归0,说明我们还需要继续取负。此时剩余的数字都是正数,所以我们对最小的数字取负即可。有以下两种情况
  1. 剩余k为偶数,因为-(-1) = 1.也就是对一个正数x取负偶数次,结果依然是x
  2. 剩余k为奇数,因为奇数-1为偶数。也就是我们对正数x先取负偶数次,结果依然是x次,然后再对其取负1次即可。简单来说,对剩余数字中最小的取负一次,然后对sum处理即可
  3. 注意:对一个sum中的一个正数取负,需要减去两个它。注意和上面将sum中一个负数取负区分。
代码
  1. 使用数组充当hash表的效率
    在这里插入图片描述
  2. 使用HashMap的效率(所以不使用这种方法,从而将这道题的难度又提升了一些)
    在这里插入图片描述

代码中的细节:普通使用hash表的效率很低,所以这道题想要超越100%的用户,需要使用数组充当hash表,这也是为什么这道题不是简单题的原因(新手很难转过来这个弯)

  1. 用数组充当hash表,因为题目所给取值范围为[-100 , 100],所以我们需要一个大小为201的数组充当hash表。也可以直接用HashMap(但是对于做题来说,效率就慢了)
  2. hash数组下标从0开始,则下标0代表-100.下标1代表-99,…,下标100代表0,…,下标200代表100
  3. 对于一个数字i来说,需要+100才是hash数组中对应的位置,因为-100+100 = 0,正好存在hash[0]的位置
  4. 既然hash[100]代表数字0,那么hash[100] 保存正数 hash[200]
  5. 对于一个负数来说,对其取负后,他变为正数,应该存放到hash[200-i]的位置,例如-100取负为100,-100原本在hash[0],则 i = 0. 此时变成正数后,应该存放到hash[200]. 也就是hash[200-(0)] ==>hash[200]
class Solution {
    public int largestSumAfterKNegations(int[] nums, int k) {
        int[] arr = new int[201];//hash表,这道题的范围是-100到100,正好需要201个位置存储。下标0表示-100
        int sum = 0;//保存当前nums数组的和
        for(int n : nums){
            arr[n+100]++;//统计元素出现次数
            sum += n;//统计当前所有元素的和
        }
        for(int i = 0; i < 100 && k > 0; i++){//从小到大遍历hash表中的负数
            if(arr[i] != 0){//如果当前数字还有剩余
                //如果当前数字i出现次数 < k ,则获取i的出现次数
                //如果当前数字i的出现次数 > k, 则获取k,表示剩余可以取负的次数
                int min = Math.min(arr[i],k);//获取当前数字的出现次数和k,较小的一个
                k -= min;//对当前数字i,每一个都取负,k表示可取负的次数,需要对min个i取负
                //负数取负后,变为正数,i = 0表示的是-100,取负变为100,应该存储在i = 200的位置,
                //i = 200表示的是正100
                arr[200-i] += min;//对min个i取负,则变为min个正i。存放到相应位置
                //5 + (-1) = 4 , 5 + 1 = 6; ==> 4 + 1*2 = 6 
                //sum + (-x) = newSum, 取负 newSum + 2 * x = newNewSum
                //当一个和的结果中,将一个负数取负后,需要加上两个它哦
                //我们这里只将负数转为正数,例如将i(0<=i<100)转为正数,是200-i
                //但是因为sum中取负某个负数i后,需要加上两个i,因此是200-2*i
                //我们一共取负了min个i,故需要(200-2*i) * min
                sum += (200-2*i)*min;
            }
        }
        //如果所有负数全部取负后,k还是没有归0,也就是我们必须继续对数字取负
        //因为k剩偶数个时,我们对同一个取负,结果不变,例如x取负两次,-(-x) = x
        //如果k还剩奇数个,就需要对某个数继续取负一次,因为 奇数 减去 1 为偶数,偶数次取负,原值不变,则剩一次需要取负
        if(k % 2 != 0){
            for(int i = 100; i <= 200; i++){//因为没有负数了,则对现存最小的数字取反一次即可
                if(arr[i] != 0){//如果当前数字存在
                    sum -= (i-100)*2;//对其取负,对一个sum中的一个正数取负,需要减去两个它
                    return sum;//返回最终结果
                }
            }
        }
        return sum;//如果在负数全部取负之前(正好全取负完)k就归0了,直接返回sum即可
    }
}

标签:LeetCode1005,hash,int,sum,取反,负数,java,100,取负
From: https://blog.csdn.net/grd_java/article/details/136765577

相关文章

  • java数据结构与算法刷题-----LeetCode134. 加油站
    java数据结构与算法刷题目录(剑指Offer、LeetCode、ACM)-----主目录-----持续更新(进不去说明我没写完):https://blog.csdn.net/grd_java/article/details/123063846文章目录1.贪心2.动态规划1.贪心解题思路:时间复杂度O(......
  • 基于Java中的SSM框架实现宝康药房销售管理系统项目【项目源码+论文说明】
    基于Java中的SSM框架实现宝康药房销售管理系统演示摘要随着我国市场经济的蓬勃发展和人们对医药产品需求的迅速增加,医药销售行业正处于一个高速发展的时期。行业的快速发展必然导致竞争的加剧,面对药品销售业日益严酷的竟争现实,加强管理、提高工作效率和改善服务质量成了急......
  • Java基础面试题(2)
    概要本文旨在帮助读者更好地准备Java基础面试,通过详细解析常见的Java基础面试题,让读者对Java语言的核心概念有更深入的理解和掌握。文章将围绕Java的语法基础、面向对象编程、异常处理、集合框架、多线程编程以及输入输出流等关键领域展开,为面试者提供全面的指导和参考。1.解......
  • java判断拼音字符串是不是汉字全拼
    publicstaticvoidmain(String[]args){Stringstr="wange";Stringstr1="huanggong";Stringstr2="wang文胜";Stringstr3="heihiyijiaren";Stringstr4="huangt......
  • java中的String
    java中String类型1.JVM(内存图)要明白java中的String类型的存储,首先要搞清楚JVM的内部方法区(主要用于存放方法)类常量池静态常量池字符串常量池(避免频繁的创建和销毁字符串,实现了数据的共享,提高了系统的性能)栈区堆区程序计数区本地方法栈2.创建一个字符串publ......
  • LeetCode 217 存在重复元素(JAVA)
    LeetCode217存在重复元素(JAVA)一、题目描述:给你一个整数数组nums。如果任一值在数组中出现至少两次,返回true;如果数组中每个元素互不相同,返回false。示例1:输入:nums=[1,2,3,1]输出:true示例2:输入:nums=[1,2,3,4]输出:false示例3:输入:nums=[1,1,1,3,3,4,......
  • LeetCode 242 有效的字母异位词(JAVA)
    LeetCode242有效的字母异位词(JAVA)一、题目描述:给定两个字符串s和t,编写一个函数来判断t是否是s的字母异位词。注意:若s和t中每个字符出现的次数都相同,则称s和t互为字母异位词。示例1:输入:s="anagram",t="nagaram"输出:true示例2:输入:s=......
  • java核心技术卷1 第六章:接口、lambda表达式与内部类
    接口接口不是类,而是描述了符合这个接口的类应该做什么,描述了一组抽象的需求,而没有指定怎么做接口中的所有方法自动是public,接口中声明方法不需要加public(java规范,减少不必要的冗余声明,即使一些程序员为了清晰习惯加上public)实现接口时,需要加上public,不然默认将权限设为了defa......
  • 身份证文字识别ocr免费-身份证实名认证接口-护照识别-Java调用代码
    文字识别技术是针对图片上的文字进行提取,免去人们手动输入的繁琐。针对证件,翔云提供了身份证识别接口、身份证实名认证接口、护照识别接口,身份证识别接口自动提取身份证信息、身份证实名认证接口实时联网查验身份证的真伪。以身份证识别接口Java语言代码为例,欢迎免费体验:pac......
  • JAVA接口代码-从技术到创新、发票ocr、发票查验接口、发票识别
    财政类票据ocr、增值税发票识别、全电票ocr接口是一项重要的技术创新,在数字化、信息化高速发展的商业环境中发挥着至关重要的作用。通过集成翔云API,可快速实现发票信息的自动化识别提取与真伪查验,提升了财务管理效率。就发票识别接口,提供Java语言代码,有需要的人员可在线......