05.位图和比较器的简单应用

位图和比较器的简单应用

一、位图

1.位图的功能

记录信息

例如,用一个 int 类型的变量的每个二进制位来记录 0 − 31 0-31 031 的出现情况。

2.位图的好处

可以用更小的空间来实现 map 的功能。

3.位图的实现

import java.util.HashSet;

public class Code02_BitMap2 {

    // 位图的实现
    public static class BitMap {

        private long[] bits;

        public BitMap(int max) {
            bits = new long[(max + 64) >> 6];
        }

        public void add(int num) {
            // 注意要用 1L
            bits[num >> 6] |= (1L << (num & 63));
        }

        public void delete(int num) {
            bits[num >> 6] &= ~(1L << (num & 63));
        }

        public boolean contains(int num) {
            return (bits[num >> 6] & (1L << (num & 63))) != 0;
        }

    }

    //对数器
    public static void main(String[] args) {
        System.out.println("测试开始!");
        int max = 10000;
        BitMap bitMap = new BitMap(max);
        HashSet<Integer> set = new HashSet<>();
        int testTime = 10000000;
        for (int i = 0; i < testTime; i++) {
            int num = (int) (Math.random() * (max + 1));
            double decide = Math.random();
            if (decide < 0.333) {
                bitMap.add(num);
                set.add(num);
            } else if (decide < 0.666) {
                bitMap.delete(num);
                set.remove(num);
            } else {
                if (bitMap.contains(num) != set.contains(num)) {
                    System.out.println("Oops!");
                    break;
                }
            }
        }
        for (int num = 0; num <= max; num++) {
            if (bitMap.contains(num) != set.contains(num)) {
                System.out.println("Oops!");
            }
        }
        System.out.println("测试结束!");
    }

}

二、用位运算实现加减乘除

用位运算实现+ - * /

1.加法

// 测试链接:https://leetcode.cn/problems/bu-yong-jia-jian-cheng-chu-zuo-jia-fa-lcof/
public class BitAddMinusMultiDiv {

    public static int add(int a, int b) {
        int sum = a;
        while (b != 0) {
            sum = a ^ b;  // 不进位和
            b = (a & b) << 1;  // 进位和
            a = sum;
        }
        return sum;
    }

}

2.减法

// 测试链接: 无
public class BitAddMinusMultiDiv {

    // a - b   =>   a + (-b) 
    public static int minus(int a, int b) {
        return add(a, negNum(b));
    }

    // n  =>  -n
    public static int negNum(int n) {
        return add(~n, 1);
    }

    public static int add(int a, int b) {
        int sum = a;
        while (b != 0) {
            sum = a ^ b;
            b = (a & b) << 1;
            a = sum;
        }
        return sum;
    }

}

3.乘法

原理同十进制乘法

// 测试链接:https://leetcode.cn/problems/recursive-mulitply-lcci/
public class BitAddMinusMultiDiv {

    // 递归方法 支持负数
    public int multiply(int A, int B) {
        if (B == 0) return 0;
        if (B == 1) return A;
        return multiply(A, (B & 1)) + multiply(A << 1, B >>> 1);
    }

    // 非递归方法 支持负数
    // a * b   =>  a 逐位乘 b 的二进制 ,并且错位相加
    public static int multi(int a, int b) {
        int res = 0;
        while (b != 0) {
            if ((b & 1) != 0) {
                res = add(res, a); // 加错位后的结果
            }
            a <<= 1; // a 左移一位 即错位
            b >>>= 1; // b 无符号右移一位,即消除最右边用过的一位数
        }
        return res;
    }

    public static int add(int a, int b) {
        int sum = a;
        while (b != 0) {
            sum = a ^ b;
            b = (a & b) << 1;
            a = sum;
        }
        return sum;
    }

}

4.除法

// 测试链接:https://leetcode.cn/problems/divide-two-integers/
public class BitAddMinusMultiDiv {

    public static int add(int a, int b) {
        int sum = a;
        while (b != 0) {
            sum = a ^ b;
            b = (a & b) << 1;
            a = sum;
        }
        return sum;
    }

    public static int negNum(int n) {
        return add(~n, 1);
    }

    public static int minus(int a, int b) {
        return add(a, negNum(b));
    }

    public static int multi(int a, int b) {
        int res = 0;
        while (b != 0) {
            if ((b & 1) != 0) {
                res = add(res, a);
            }
            a <<= 1;
            b >>>= 1;
        }
        return res;
    }

    public static boolean isNeg(int n) {
        return n < 0;
    }

    public static int div(int a, int b) {
        int x = isNeg(a) ? negNum(a) : a;
        int y = isNeg(b) ? negNum(b) : b;
        int res = 0;
        for (int i = 30; i >= 0; i = minus(i, 1)) {
            if ((x >> i) >= y) {
                res |= (1 << i);
                x = minus(x, y << i);
            }
        }
        return isNeg(a) ^ isNeg(b) ? negNum(res) : res;
    }

    public static int divide(int a, int b) {
        if (a == Integer.MIN_VALUE && b == Integer.MIN_VALUE) {
            return 1;
        } else if (b == Integer.MIN_VALUE) {
            return 0;
        } else if (a == Integer.MIN_VALUE) {
            if (b == negNum(1)) {
                return Integer.MAX_VALUE;
            } else {
                // a / b
                // (a + 1) / b == c
                // a - (b * c) = d
                // d / b = e
                // c + e
                int c = div(add(a, 1), b);
                return add(c, div(minus(a, multi(c, b)), b));
            }
        } else {
            return div(a, b);
        }
    }

}

三、位运算完成大小比较

如何不用任何比较判断语句,就可以返回两个数中较大的那个

/**
 * @author 杨思远
 * @version 1.0
 * @title 位运算完成大小比较
 * @date 2022/7/16 0:52
 * @description 本方法原创 不一定为最优解    a < b => -1     a == b => -1     a > b => 1
 */
public class BitComparisonOfSize {

    // 只使用 !=
    public static int compare(int a, int b) {
        if (a >>> 31 != b >>> 31) return b >>> 31 - a >>> 31;
        for (int i = 30; i > 0; i--) {
            if (a >>> i != b >>> i) return a >>> i - b >>> i;
        }
        return 0;
    }

    // 不使用任何比较判断语句 ( > < = != >= <= )
    public static int compare2(int a, int b) {
        return a - b >>> 31;
    }

    public static void main(String[] args) {
        System.out.println("测试开始");
        for (int i = 0; i < 1000000; i++) {
            int a = (int) (Math.random() * Integer.MIN_VALUE) * Math.random() < 0.5 ? 1 : -1;
            int b = (int) (Math.random() * Integer.MIN_VALUE) * Math.random() < 0.5 ? 1 : -1;
            int res = compare(a, b);
            int res2 = compare2(a, b);
            int acceptedAnswer = Integer.compare(a, b);
            if (res != acceptedAnswer || res2 != acceptedAnswer) {
                System.out.println("错误:a:" + a + ",b:" + b);
            }
        }
        System.out.println("测试结束");
    }

}

四、比较器

1.应用在系统排序方法中

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;

public class ShowComparator {

   public static class Student {
      public String name;
      public int id;
      public int age;

      public Student(String name, int id, int age) {
         this.name = name;
         this.id = id;
         this.age = age;
      }
   }

   // 谁id大,谁放前!
   public static class IdComparator implements Comparator<Student> {

      // 如果返回负数,认为第一个参数应该排在前面
      // 如果返回正数,认为第二个参数应该排在前面
      // 如果返回0,认为谁放前面无所谓
      @Override
      public int compare(Student o1, Student o2) {
         if (o1.id < o2.id) {
            return 1;
         } else if (o2.id < o1.id) {
            return -1;
         } else {
            return 0;
         }
      }
   }
   
   // 谁age大,谁放前!
   public static class AgeComparator implements Comparator<Student> {

      // 如果返回负数,认为第一个参数应该排在前面
      // 如果返回正数,认为第二个参数应该排在前面
      // 如果返回0,认为谁放前面无所谓
      @Override
      public int compare(Student o1, Student o2) {
         if (o1.age < o2.age) {
            return 1;
         } else if (o2.age < o1.age) {
            return -1;
         } else {
            return 0;
         }
      }
   }

   public static void printArray(int[] arr) {
      for (int i = 0; i < arr.length; i++) {
         System.out.print(arr[i] + " ");
      }
      System.out.println();
   }

   public static void printStudents(Student[] students) {
      for (int i = 0; i < students.length; i++) {
         System.out.println(students[i].name + ", " + students[i].id + ", " + students[i].age);
      }
   }

   public static void main(String[] args) {
      int[] arr = { 8, 1, 4, 1, 6, 8, 4, 1, 5, 8, 2, 3, 0 };
      printArray(arr);
      Arrays.sort(arr);
      printArray(arr);

      Student s1 = new Student("张三", 5, 27);
      Student s2 = new Student("李四", 1, 17);
      Student s3 = new Student("王五", 4, 29);
      Student s4 = new Student("赵六", 3, 9);
      Student s5 = new Student("左七", 2, 34);

      Student[] students = { s1, s2, s3, s4, s5 };
      printStudents(students);
      System.out.println("=======");
      Arrays.sort(students, new IdComparator());
      printStudents(students);
      System.out.println("=======");

      ArrayList<Student> arrList = new ArrayList<>();
      arrList.add(s1);
      arrList.add(s2);
      arrList.add(s3);
      arrList.add(s4);
      arrList.add(s5);
      for (Student s : arrList) {
         System.out.println(s.name + ", " + s.id + ", " + s.age);
      }
      System.out.println("=======");
      arrList.sort(new AgeComparator());
      for (Student s : arrList) {
         System.out.println(s.name + ", " + s.id + ", " + s.age);
      }

   }

}

2.应用在与排序有关的结构中优先级队列(堆)、有序表

import java.util.Comparator;
import java.util.PriorityQueue;

public class ShowComparator2 {

   public static class MyComparator implements Comparator<Integer> {

      // 负,第一个参数在前
      // 正,第二个参数在前
      // 0, 谁放前都行
      @Override
      public int compare(Integer o1, Integer o2) {
         if (o1 < o2) {
            return 1;
         } else if (o1 > o2) {
            return -1;
         } else {
            return 0;
         }
      }

   }

   public static class Student {
      public String name;
      public int id;
      public int age;

      public Student(String name, int id, int age) {
         this.name = name;
         this.id = id;
         this.age = age;
      }
   }

   // 谁id大,谁放前!
   public static class IdComparator implements Comparator<Student> {

      // 如果返回负数,认为第一个参数应该排在前面
      // 如果返回正数,认为第二个参数应该排在前面
      // 如果返回0,认为谁放前面无所谓
      @Override
      public int compare(Student o1, Student o2) {
         if (o1.id < o2.id) {
            return 1;
         } else if (o2.id < o1.id) {
            return -1;
         } else {
            return 0;
         }
      }
   }

   public static void main(String[] args) {
      String str1 = "abc";
      String str2 = "b";
      System.out.println(str1.compareTo(str2));
      PriorityQueue<Student> heap = new PriorityQueue<>(new IdComparator());
      Student s1 = new Student("张三", 5, 27);
      Student s2 = new Student("李四", 1, 17);
      Student s3 = new Student("王五", 4, 29);
      Student s4 = new Student("赵六", 3, 9);
      Student s5 = new Student("左七", 2, 34);
      heap.add(s1);
      heap.add(s2);
      heap.add(s3);
      heap.add(s4);
      heap.add(s5);
      System.out.println("=========");
      while (!heap.isEmpty()) {
         Student s = heap.poll();
         System.out.println(s.name + ", " + s.id + ", " + s.age);
      }
   }

}

五、合并多个有序链表

Leetcode原题 https://leetcode.com/problems/merge-k-sorted-lists

import java.util.Comparator;
import java.util.PriorityQueue;
// 时间复杂度 O(M*log(N))
// 测试链接:https://leetcode.cn/problems/merge-k-sorted-lists/
public class MergeKSortedLists {

   public static class ListNode {
      public int val;
      public ListNode next;
   }

   public static class ListNodeComparator implements Comparator<ListNode> {

      @Override
      public int compare(ListNode o1, ListNode o2) {
         return o1.val - o2.val; 
      }

   }

   public static ListNode mergeKLists(ListNode[] lists) {
      if (lists == null) {
         return null;
      }
      PriorityQueue<ListNode> heap = new PriorityQueue<>(new ListNodeComparator());
      for (int i = 0; i < lists.length; i++) {
         if (lists[i] != null) {
            heap.add(lists[i]);
         }
      }
      if (heap.isEmpty()) {
         return null;
      }
      ListNode head = heap.poll();
      ListNode pre = head;
      if (pre.next != null) {
         heap.add(pre.next);
      }
      while (!heap.isEmpty()) {
         ListNode cur = heap.poll();
         pre.next = cur;
         pre = cur;
         if (cur.next != null) {
            heap.add(cur.next);
         }
      }
      return head;
   }

}

六、写在后面

欢迎关注,会经常记录一些算法学习中遇到的问题。

欢迎随时留言讨论,与君共勉,知无不答!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: CMOS运算放大器是一种使用互补金属氧化物半导体(CMOS)技术制造的放大器。它具有低功耗、高增益、高带宽和高线性度的特点。CMOS运算放大器通常由差动输入级、差动放大级和输出级组成。它可以被广泛应用于模拟信号处理和模拟电路设计。 CMOS运算放大器的设计需要考虑增益、带宽、功耗和线性度等关键参数。在设计过程中,需要合理选择晶体管的尺寸和电流偏置,以实现所需的性能。 CMOS比较器是一种将输入信号与参考电平进行比较并输出高/低电平的电路。它通常由差动对放大器、纵向偏置电路和输出电路组成。CMOS比较器常用于模拟与数字信号之间的界面电路,如模数转换器(ADC)和振荡器的输入端。 CMOS比较器的设计需要考虑响应时间、功耗、噪声和输入电压范围等因素。一些常用的技术,如共源共漏(CS-CMOS)比较器、交叉耦合比较器和基于电压控制的CMOS比较器等,可以用于提高性能。 总之,CMOS运算放大器和比较器是现代电子技术中常见的功能模块。它们的设计与应用可以帮助实现模拟信号的处理和电路之间的界面转换。 ### 回答2: CMOS运算放大器是一种基础的电子器件,用于放大输入信号的幅度。其设计可以通过调整电阻和电流源的参数来实现不同的放大倍数和频率响应。CMOS运算放大器采用互补金属氧化物半导体(CMOS)技术制造,结合了MOSFET的高输入阻抗和增益稳定性,以及CMOS的低功耗和高集成度。 CMOS运放的应用广泛,常用于模拟信号处理和电压放大等领域。在模拟信号处理方面,它可以用于音频放大器、传感器信号放大和滤波等。CMOS运放的低功耗特性使其在电池供电的便携设备中得到广泛应用。而在电压放大方面,CMOS运放也可以作为信号放大器,将微弱的输入信号放大到合适的幅度用于后续电路的处理。 比较器是另一类常见的电子器件,用于对输入信号进行比较,并输出相应的开关信号。它的设计是为了快速准确地检测输入信号与参考电平的关系。CMOS比较器可以利用MOSFET的高输入阻抗和快速开关速度,实现快速响应和低功耗。 CMOS比较器在数字信号处理、模拟信号过滤和开关电路等方面有重要应用。例如,在ADC(模数转换器)中,CMOS比较器用于将模拟输入信号与参考电压进行比较,并输出一个数字信号。在模拟信号过滤方面,它可以用于实现信号的开关和切换。CMOS比较器也常用于模数信号中的采样保持电路或触发器等。 总之,CMOS运算放大器和比较器是电子领域中重要的器件,其灵活的设计和广泛的应用使它们成为现代电子电路中不可或缺的组成部分。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值