算法-力扣

整数的反转

给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。

如果反转后整数超过 32 位的有符号整数的范围 [−231, 231 − 1] ,就返回 0。

假设环境不允许存储 64 位整数(有符号或无符号)。

在这里插入图片描述

 public int reverse(int x) {
           long n = 0;
        while(x != 0) {
            n = n*10 + x%10; //数学公式
            x = x/10;
        }
        return (int)n==n? (int)n:0; //将n强转为int类型 若强转不成功说明溢出 因为long类型是64位
    }
  

删除数组中的重复项

一个有序数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。
不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。

解题思路:使用快慢指针的思想

 public int removeDuplicates(int[] nums) {
  if (nums == null || nums.length == 1) {
              return nums.length;
          }
          int j = 0;
        for(int i=0;i<nums.length;i++){
            if(nums [j]!=nums[i]){ //找不同的数值
                nums [j+1]=nums[i];
                j++;
            }
          }
          return j + 1;
      }
    }

最小的k个数

输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。
思路:使用快排
快排:给定一个基准 高位 低位
若high大于基准 high-- 高位的值给低位
low小于基准 low++ 低位的值给高位

//快排的思想
 private int[] quicksort(int[]arr,int high,int low,int val){
         if (low >= high) {
             return Arrays.copyOf(arr,val);
         }
        int mind=partition(arr,high,low);
         if(low+1 <mind){
             quicksort(arr,mind-1,low,val);
         }
         if(high-1 >mind){
             quicksort(arr,high,mind+1,val);
         }
           return Arrays.copyOf(arr,val);
    }
public int[] getLeastNumbers(int[] arr, int k) {
           if(k==0||arr.length==0){
                return new int[0];
           }
          return quicksort(arr,arr.length -1,0,k);
    }
   //因为是找最小的k个数 所以只用排序前k个数然后复制返回就好
 private int[] quicksort(int[]arr,int high,int low,int val){
         if (low >= high) {
             return Arrays.copyOf(arr,val);
         }
        int mind=partition(arr,high,low);
         if(mind == val) {
            return Arrays.copyOf(arr, val);
        }
      return mind>val?quicksort(arr,mind-1,low,val):quicksort(arr,high,mind+1,val);
    }

    private int partition(int[] array, int high, int low){
           int por=array[low];
           while(low<high){
              while (low < high && array[high] >= por) {
                  high--;
               }
               if(low==high){
                   break;
               }
               array[low]=array[high];
              while (low < high && array[low] <= por) {
                      low++;
               }
               if(low==high){
                   break;
               }
               array[high]=array[low];
           }
           array[low] = por;
        return low;
    }  
}

堆排 没快排速度快
大根堆

public int[] getLeastNumbers(int[] arr, int k) {
           if(k==0||arr.length==0){
                return new int[0];
           }
            //传自定义的比较器 默认是小根堆,实现大根堆需要重写一下比较器。
 Queue<Integer>  queue = new PriorityQueue<Integer>((o1, o2) ->o2-o1 );
         for(int a:arr){
           if(queue.size()<k){
               queue.offer(a);
           }else if(a<queue.peek()){
               queue.poll();
               queue.offer(a);
           }
        }  
        int [] ary=new int[k];
        int idx=0;
        for(int a:queue){
            ary[idx++]=a;
        }
        return ary;
    }
   

二叉搜索树

  public int[] getLeastNumbers(int[] arr, int k) {
        if (k == 0 || arr.length == 0) {
            return new int[0];
        }
        // TreeMap的key是数字, value是该数字的个数。
        // cnt表示当前map总共存了多少个数字。
        TreeMap<Integer, Integer> map = new TreeMap<>();
        int cnt = 0;
        for (int num: arr) {
            // 1. 遍历数组,若当前map中的数字个数小于k,则map中当前数字对应个数+1
            if (cnt < k) {
                map.put(num, map.getOrDefault(num, 0) + 1);
                cnt++;
                continue;
            } 
            // 2. 否则,取出map中最大的Key(即最大的数字), 判断当前数字与map中最大数字的大小关系:
            //    若当前数字比map中最大的数字还大,就直接忽略;
            //    若当前数字比map中最大的数字小,则将当前数字加入map中,并将map中的最大数字的个数-1。
            Map.Entry<Integer, Integer> entry = map.lastEntry();
            if (entry.getKey() > num) {
                map.put(num, map.getOrDefault(num, 0) + 1);
                if (entry.getValue() == 1) {
                    map.pollLastEntry();
                } else {
                    map.put(entry.getKey(), entry.getValue() - 1);
                }
            }
            
        }

        // 最后返回map中的元素
        int[] res = new int[k];
        int idx = 0;
        for (Map.Entry<Integer, Integer> entry: map.entrySet()) {
            int freq = entry.getValue();
            while (freq-- > 0) {
                res[idx++] = entry.getKey();
            }
        }
        return res;
    }

第一个只出现一次的字符串

s = “abaccdeff” 返回 “b”
s = “” 返回 " "

public char firstUniqChar(String s) {
        for (int i = 0; i < s.length(); i++) {
           char ch=s.charAt(i);
           
           //首次出现的位置是当前位置,且后面没有再出现这个字符
            if(s.indexOf(ch)==i&&s.indexOf(ch,i+1)==-1)
                return s.charAt(i);
        }
        return ' ';
    }
 public char firstUniqChar(String s) {
        Map<Character, Integer> map = new LinkedHashMap();
        for(int i=0; i<s.length(); i++){
            char c = s.charAt(i);
            map.put(c, map.getOrDefault(c, 0)+1);
        }

        for(char ch: map.keySet()){
            if(map.get(ch)==1)
                return ch;
        }

        return ' '; 
    }

和为s的两个数字

输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s。如果有多对数字的和等于s,则输出任意一对即可。

输入:nums = [2,7,11,15], target = 9
输出:[2,7] 或者 [7,2]

public int[] twoSum(int[] nums, int target) {
        int prv=0;
        int fast =nums.length-1;
        while(prv<fast){
            int sum =nums[prv]+nums[fast];
            if(sum==target){
                return new int[]{nums[prv],nums[fast]};
            }
            else if(sum>target){
                 fast--;
            }else{
                prv++;
            }
        }
        return new int[0];
    }

和为s的正数序列

输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数)。
序列内的数字由小到大排列,不同序列按照首个数字从小到大排列。
输入:target = 9
输出:[[2,3,4],[4,5]]
思路:滑动窗口

public static int[][] findContinuousSequence(int target) {
          List<int[]> list = new ArrayList<>();

        for (int l = 1, r = 1, sum = 0; r < target; r++) {
            sum += r;
            while (sum > target) {
                sum -= l++;
            }
            if (sum == target) {
                int[] temp = new int[r - l + 1];
                for (int i = 0; i < temp.length; i++) {
                    temp[i] = l + i;
                }
                list.add(temp);
            }
        }

        int[][] res = new int[list.size()][];
        for (int i = 0; i < res.length; i++) {
            res[i] = list.get(i);
        }
        return res;
    }

翻转单词

输入: “the sky is blue”
输出: “blue is sky the”
也就是说,trim()方法实际上的行为并不是”去掉两端的空白字符“,而是”截取中间的非空白字符“。

  public String reverseWords(String s) {
        //trim是截取中间的字符串 去掉两边的空格
          String sc[]=s.trim().split(" ");
            StringBuilder StringBudder=new StringBuilder();

            for(int i=sc.length-1;i>=0;i--){
                if (sc[i].equals("")) {
                continue;
            }
            //    到头了,append然后去空格 
            if (i == 0) {
                StringBudder.append(sc[i].trim());
            } else {
                // 怕有多余的空格,去掉,再加上去
                StringBudder.append(sc[i].trim()).append(" ");
           }
            }return StringBudder.toString();
    }

调整数组使得奇数在前

输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分。
输入:nums = [1,2,3,4]
输出:[1,3,2,4]
注:[3,1,2,4] 也是正确的答案之一

public int[] exchange(int[] nums) {
        int left = 0;
        int right = nums.length - 1;
        while (left < right) {
            while (left < right && nums[left] % 2 != 0) {
                left++;
            }
            while (left < right && nums[right] % 2 == 0) {
                right--;
            }
            if (left < right) {
                int temp = nums[left];
                nums[left] = nums[right];
                nums[right] = temp;
            }
        }
        return nums;
    }

第一次出现的字符

在字符串 s 中找出第一个只出现一次的字符。如果没有,返回一个单空格。 s 只包含小写字母。

 public char firstUniqChar(String s) {
       for (int i = 0; i < s.length(); i++) {
           char ch=s.charAt(i);
           
           //首次出现的位置是当前位置,且后面没有再出现这个字符
            if(s.indexOf(ch)==i&&s.indexOf(ch,i+1)==-1)
                return s.charAt(i);
        }
        return ' ';
    }

二进制中1的个数

请实现一个函数,输入一个整数(以二进制串形式),输出该数二进制表示中 1 的个数。例如,把 9 表示成二进制是 1001,有 2 位是 1。因此,如果输入 9,则该函数输出 2。

输入:00000000000000000000000000001011
输出:3
解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 ‘1’。

思路:
根据 与运算 定义,设二进制数字 nn ,则有:
若 n & 1 = 0,则 n 二进制 最右一位 为 0 ;
若 n & 1 = 1 ,则 n 二进制 最右一位 为 1 。
根据以上特点,考虑以下 循环判断 :
判断 n 最右一位是否为 1 ,根据结果计数。
将 n 右移一位(本题要求把数字 n 看作无符号数,因此使用 无符号右移 操作)。

 public int hammingWeight(int n) {
        int res = 0;
        while(n != 0) {
            res += n & 1;
            n >>>= 1;
        }
        return res;
    }

思路2:
(n−1) 解析: 二进制数字 n 最右边的 1 变成 0 ,此 1 右边的 0 都变成 1 。
n & (n - 1) 解析: 二进制数字 n 最右边的 1 变成 0 ,其余不变。

public int hammingWeight(int n) {
        int res = 0;
        while(n != 0) {
            res++;
            n &= n - 1;
        }
        return res;
    }

数组中出现次数超过数组长度一半的数字

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。

public int majorityElement(int[] nums) {
        //getOrDefault(Object key, V defaultValue)
        //这个判断是否含有key的键值对、若存在返回key的val,否则返回defaultValue
     Map<Integer,Integer> map = new HashMap<>();
        for(int num :nums){
            map.put(num,map.getOrDefault(num,0)+1);
            if(map.get(num)> nums.length>>1) return num;
        }
        return 0;
} 
 //若存在数大于数组一半的长度
    public int majorityElement(int[] nums) { 
        Arrays.sort(nums);
        return nums[nums.length/2]
    }

  //采用摩尔投票法
   public int majorityElement(int[] nums) { 
       int count=0;
       Integer  vouat = null;
       for(int num:nums){
           if(count==0) vouat=num;
           count +=(vouat==num)?1:-1;
       }

   }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值