算法准备-4.21

算法准备-4.21

1. 第一个只出现一次的字符

  1. 描述:在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写).

  2. 思路:这是我第一次使用哈希表,首先遍历一遍字符数组,查看每个字符的个数,第二次遍历时找到第一个数量为1的字符即可

  3. 题解:

    class Solution {
        public char firstUniqChar(String s) {
            HashMap<Character,Boolean> res=new HashMap<>();
            char[] target=s.toCharArray();
            for(char c:target)
            {
                res.put(c,!res.containsKey(c));
            }
            for(char c:target)
            {
                if(res.get(c)) return c;
            }
            return ' ';
        }
    }
    
  4. 改进:在字符串较长的时候(重复字符很多),因为哈希表有去重的功能,所以此时使用有序哈希表,然后遍历有序哈希表的效率更高

  5. 改进后的题解:

    class Solution {
        public char firstUniqChar(String s) {
            Map<Character,Boolean> res=new LinkedHashMap<>();
            char[] target=s.toCharArray();
            for(char c:target)
            {
                res.put(c,!res.containsKey(c));
            }
            for(Map.Entry<Character,Boolean> d:res.entrySet())
            {
                if(d.getValue()) return d.getKey();
            }
            return ' ';
        }
    }
    

2. 数组中的逆序对

先导知识点:归并排序

归并排序实际上是一个分治的思想,不停的将数组分成两半,递归的进行处理,直至只剩一个元素的时候,对相邻的有序序列进行合并,合并的过程就是建立一个辅助数组,合并两个有序数组,用空间换时间

  1. 描述:在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。

  2. 思路:暴力解法就是用两个循环即可,但是在这题的例子中会超时,我们选择用改进的归并排序,当两个有序数组合并时,当后半部分的有序数组出列时,计算前半部分中还剩多少数未出列,即为比他大的数,当后有序数组出列完后,前有序数组的元素出列时不必计算逆序对数,其数已在第一步时计算过

  3. 题解:

    class Solution {
        public int reversePairs(int[] nums) {
            int len=nums.length;
            if(len<2)
            {
                return 0;
            }
            int[] temp=new int[len];
            return reverse(nums,0,len-1,temp);
        }
    
        public int reverse(int[] nums,int left,int right,int[] temp)
        {
            if(left==right)
            {
                return 0;
            }
            int mid=(left+right)/2;
            int leftpairs=reverse(nums,left,mid,temp);
            int rightpairs=reverse(nums,mid+1,right,temp);
            int reversepairs=leftpairs+rightpairs;
            int crosspairs=mergesort(nums,left,mid,right,temp);
            return reversepairs+crosspairs;
        }
    
        public int mergesort(int[] nums,int left,int mid,int right,int[] temp)
        {
            for(int i=left;i<=right;i++)
            {
                temp[i]=nums[i];
            }
            int i=left;
            int j=mid+1;
            int res=0;
            for(int k=left;k<=right;k++)
            {
                if(i>mid)
                {
                    nums[k]=temp[j];
                    j++;
                }
                else if(j>right)
                {
                    nums[k]=temp[i];
                    i++;
                }
                else if(temp[i]<=temp[j])
                {
                    nums[k]=temp[i];
                    i++;
                }
                else
                {
                    nums[k]=temp[j];
                    j++;
                    res+=(mid-i+1);//最关键的就在这一步,一次加一个区间
                }
            }
            return res;
        }
    }
    

    实际上就是在归并合并的时候计算逆序对,本题采用的时在后有序数组出列的时候计算逆序对

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值