ARTS习惯(8)

Algorithm

每周至少做一个Leetcode算法题

第1道

【来源】

《剑指Offer》10#

Leetcode 191#

【题目】

设计一个函数,输入整数n,输出n的二进制表示中1的个数

例子

输入:8
输出:1
解释:8的二进制表示1000

【解答】

如果第一直觉是用除k取余法,那证明你的基础不错,进制转换应该学的不错。只是,除法的效率远远差于位运算。

若采用右移n,掩码固定的方案,不能解决n为负数时带来的死循环问题。

采用固定n,掩码左移的方案可以很好解决以上问题,见解法1,此方案的可以优化的地方是循环的次数

不断的将整数右边的1反转为0,反转的次数就是1的个数,此方案完善了循环次数稍多的问题

【示例代码】

package com.pengluo.hht_offer.T10_BitOperation;

public class NumberOf1InBinary {


    /**
     * 解法1.掩码法
     * 时间复杂度:O(1)
     * 空间复杂度:O(1)
     *
     * @param number
     * @return number的二进制表示中1的个数
     */
    public int getNumberOf1(int number) {
        int count = 0;
        int flag = 1;
        while (flag != 0) {
            if ((number & flag) != 0) {
                count++;
            }
            flag <<= 1;
        }
        return count;
    }

    /**
     * 解法2:定义法
     *   (n-1) & n 的效果就是将数字最后的1反转为0
     *  整数n的二进制表示中,最右边的1的位置为m,按照定义n-1的二进制表示,m位置坐左边的表示和n的一致,右边则全为1,
     *
     *  时间复杂度:O(1)
     *  空间复杂度:O(1)
     *
     * @param n
     * @return 二进制表示中1的个数
     */
    public int getNumberOf1ByDefiniton(int n) {
        int count = 0;
        while (n != 0) {
            count++;
            n &= n - 1;
        }
        return count;
    }

    /**
     * 变式1:n是否是2的整数次方
     * 解法:题目等价于求n的二进制表示中有且仅有1个1,用n-1和n做与运算就可以将1变成0
     * @param n
     * @return
     */
    public boolean isPowOfTwo(int n) {
        int count = getNumberOf1ByDefiniton(n);
        if (count == 1) {
            return true;
        }else {
            return false;
        }
    }

    /**
     * 变式2:输入source和target两个整数,返回source变成target需要改变的二进制的位数
     * 输入 source = 10, target = 13
     * 输出 3
     *
     * 解法:1.source和target做异或
     *      2.统计异或结果中1的个数
     *
     * @param source
     * @param target
     * @return
     */

    public int NumberOfChange(int source, int target) {
        int temp = source^target;
        return getNumberOf1ByDefiniton(temp);
    }

}

总结

  • 位运算的效率高于乘除法

  • (n-1)& n 达到将1反转为0的思路很使用

Review

阅读并点评至少1篇英文技术文章

【原文】:Head First Java 2nd Edition CH15

【点评】:

  • client 和 server之间的连接

    • socket 连接

      • 一个端口port只能绑定一个应用

      • port:16位无符号的数字,0~1023,为已知的应用分配了,不能使用,比如:HTTP,FTP协议

        1024~65535,程序员可以随意使用

    • client发送信息

      • // 1.和server连接
        Socket socket = new Socket("127.0.0.1", 5050);
        // 2.建立character转byte的桥梁
        PrintWriter writer = new PrintWriter(socket.getOutputStream());
        // 调用API
        writer.println("write testing");
        
    • client接受信息

      • // 1.和server建立连接
        Socket socket = new Socket("127.0.0.1", 5050);
        // 2.将底层的字节流转化为字符流
        InputStreamReader isr = new InputStreamReader(socket.getInputStream());
        // 3.缓存字符流
        BufferedReader reader = new BufferedReader(isr);
        // 使用API
        String message = reader.readLine();
        
  • 多线程

    • Thread class

      • // 和普通类一样,一个Thread类可以创建多个instance
        Thread one = new Thread();
        Thread two = new Thread();
        
    • Runnable接口

      • public class MyRunnable implements Runnable {
            @Override 
            public void run() {
                // Runnable 唯一定义的方法
                laugh();
            }
            
            // 自定义方法
            public void laugh() {}
        }
        
        
    • thread 线程执行(call stack)

      // Runnable is to thread what job is to worker.
      MyRunnable runnable = new MyRunable();
      Thread t1 = new Thread(runnable);
      Thread t2 = new Thread(runnable);
      // 线程启动后,自动执行runnable的run()方法,这是t的栈调用的最下面的方法
      t1.start();
      // 线程之间的切换,是由JVM按thread schduler自动完成,
      // 线程在running runnable blocked 三种状态进行切换
      t2.start();
      // Thread类的静态方法,休眠2s内,进入由ruuning态变成block,其他线程可以执行,2s后,进入runnable态
      // sleep的一个作用是强制让其他线程跑起来
      Thread.sleep(2000);
      
      
    • 并发问题

      • Ryan和Monica的取钱问题
        • synchronized加锁
        • atomic process
        • Object's lock
      • Lost Update问题
      • synchronized的问题
        • 影响性能表现
        • 拖慢你的程序运行
        • 最糟的是死锁问题(线程a,b分别拿着对方需要的锁的钥匙,互相等待)
        • 为了减少并发编程的死锁问题,推荐了Java Threads by Scott Oaks

Tip

学习至少一个技术技巧

重复的CRUD代码,可以抽象到公共的基类接口

泛型设计

Share

分享一篇有观点和思考的技术文章

CodingTour大神的ARTS专栏

posted @ 2021-01-12 23:34  米罗{mirror}  阅读(54)  评论(0编辑  收藏  举报