OneCoder


  • 首页

  • 归档

  • 标签

  • 关于

  • 搜索

20190728 - 全职高手

发表于 2019-07-28

早起终于基本完成了工作材料准备。

《全职高手》我是最喜欢的看的网络小说,看过很多遍。其实没什么内涵,可能因为是爽文喜欢主线的情节,或者喜欢里面主角的人物性格。总之,看的很舒服。

昨天看了电视剧,对电视剧本身无感,但足以勾起我的回忆。

大不了,从头再来。

2019年7月28日 晨

阅读全文 »

20190727 - 周末

发表于 2019-07-27

要做的事情很多:

  1. 把Office365账号同步,设置好家里的多台电脑;
  2. 准备汇报材料;
  3. 学习SQL,写总结笔记;
  4. 准备个人介绍材料
  5. 英语课;
  6. 清理下水道。
  7. 其他吧……

但,我却先写了日记,呵呵。

2019年7月27日 午

阅读全文 »

20190726-无题

发表于 2019-07-26

不知道为什么,基于gitment的评论框完全失效。看不惯这么荒废下去,找到一个替代品:基于LeanCloud的valine。理由很简单,LeanCloud我正在用,博客中的阅读量统计就是基于LeanCloud的做的。刚回家就迫不急的折腾一番,目前看应该替换成功了,未做详细测试,暂且如此吧。

刚刚,第一次喝了夺命乌苏+大凯龙,还真是有点晕,但估计是心里作用。

今天是个特殊的日子,因为昨天是我妈的生日。

2019年7月26日 晚

阅读全文 »

20190725-琐碎

发表于 2019-07-25

看了会书,本想在这个差点荒废的博客上写点总结,却发现以前写的一段创建新博文的python脚本失效。

不知道脑子里在想什么,我开始读起自己2016年有段时间在博客里写的日记。还挺有趣,除了错别字有点多。

想想早期做博客还很在意流量和SEO,整日折腾。现在在意的,恐怕是懒了吧。

既然回头看看这么有趣,就再给自己储备点食粮吧。

最近,在看数据中台和SQL。

2019年7月25日 晚

阅读全文 »

一段好看的代码注释

发表于 2019-07-17

看到一段好看的代码注释。想写在自己的程序里:

/***
 * ┌───┐   ┌───┬───┬───┬───┐ ┌───┬───┬───┬───┐ ┌───┬───┬───┬───┐ ┌───┬───┬───┐
 * │Esc│   │ F1│ F2│ F3│ F4│ │ F5│ F6│ F7│ F8│ │ F9│F10│F11│F12│ │P/S│S L│P/B│  ┌┐    ┌┐    ┌┐
 * └───┘   └───┴───┴───┴───┘ └───┴───┴───┴───┘ └───┴───┴───┴───┘ └───┴───┴───┘  └┘    └┘    └┘
 * ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐ ┌───┬───┬───┐ ┌───┬───┬───┬───┐
 * │~ `│! 1│@ 2│# 3│$ 4│% 5│^ 6│& 7│* 8│( 9│) 0│_ -│+ =│ BacSp │ │Ins│Hom│PUp│ │N L│ / │ * │ - │
 * ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤ ├───┼───┼───┤ ├───┼───┼───┼───┤
 * │ Tab │ Q │ W │ E │ R │ T │ Y │ U │ I │ O │ P │{ [│} ]│ | \ │ │Del│End│PDn│ │ 7 │ 8 │ 9 │   │
 * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴─────┤ └───┴───┴───┘ ├───┼───┼───┤ + │
 * │ Caps │ A │ S │ D │ F │ G │ H │ J │ K │ L │: ;│" '│ Enter  │               │ 4 │ 5 │ 6 │   │
 * ├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────────┤     ┌───┐     ├───┼───┼───┼───┤
 * │ Shift  │ Z │ X │ C │ V │ B │ N │ M │< ,│> .│? /│  Shift   │     │ ↑ │     │ 1 │ 2 │ 3 │   │
 * ├─────┬──┴─┬─┴──┬┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤ ┌───┼───┼───┐ ├───┴───┼───┤ E││
 * │ Ctrl│    │Alt │         Space         │ Alt│    │    │Ctrl│ │ ← │ ↓ │ → │ │   0   │ . │←─┘│
 * └─────┴────┴────┴───────────────────────┴────┴────┴────┴────┘ └───┴───┴───┘ └───────┴───┴───┘
 */
阅读全文 »

Netty4自学笔记 (3) - Netty NIO Server和Client 样例说明

发表于 2018-08-13

更新节奏缓慢,因为每晚学习注意力不够集中,学习进展缓慢。本还给自己找了一大堆其他理由,但摸着良心问自己,似乎只有这个理由说的通。

想搞懂的太多,却始终没搞明白。先看一个用Netty编写的NIO Server的样例。

package com.coderli.nettylab.guide;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

/**
 * @author lihongzhe 2018/7/24 23:19
 */
public class NettyNioServer {

    public static void main(String[] args) throws InterruptedException {
        EventLoopGroup bossGroup = new NioEventLoopGroup(); // (1)
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap(); // (2)
            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class) // (3)
                    .childHandler(new ChannelInitializer<SocketChannel>() { // (4)
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(new ServerHandler());
                        }
                    })
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .childOption(ChannelOption.SO_KEEPALIVE, true);

            ChannelFuture f = b.bind(7060).sync(); // (5)
            f.channel().closeFuture().sync();
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }

}

ServerHanler代码

package com.coderli.nettylab.guide;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

/**
 * @author lihongzhe 2018/7/24 23:58
 */
public class ServerHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        System.out.println("Receive Msg.");
        ((ByteBuf) msg).release(); 
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }
}

上述代码改自Netty官方手册。NettyNioServer代码中做了几处标记,分别对应我们在Netty4 自学笔记(2)中讨论的关键点,简析如下:

  1. 标记1是构建了两个线程池,我们在Java NIO学习中提到的,针对Select的实现方式,如果想要实现并发,只需要在事件处理时,启用多线程处理即可,此处的workerGroup正是为此服务。而在Netty中,不仅仅对于事件到达后的处理启用了线程池,为了实现高并发,Netty开启多个线程注册多个Selector同时处理事件。Netty中,默认线程池数量为,cpu核心数 * 2(NettyRuntime.availableProcessors() * 2),个人认为Selector线程数过多意义也不大,关键还是在于事件分发后的后续处理,即work线程。同样,这里worker线程池的默认数量与boss一致,因此在业务实现中应注意异步处理worker中的回调,以免堵塞worker,影响并发。
  2. 标记2的ServerBootstrap是Netty封装的统一配置并启动Server的启动器,在Java NIO学习中提到的Channel(标记3)和事件处理器Handler(标记4),都统一配置在此。标记3处指定不同类型的Channel(例如:Nio、Oio),底层便可方便的在不同的通信模式下进行切换,上层无感知。
  3. 标记5,一切配置好后,启动器绑定到指定端口。

从样例代码的直观感觉来说,Netty提供了良好的封装,无论是Server还是事件处理的Handler,Netty几乎帮我们做好了一切。对于开发人员来说,只需要关注于Netty提供的Handler的回调时机,开发自己的业务逻辑,比直接使用Java NIO的API节约了很多的开工作量,而且保证了代码的健壮性和多线程支持。

因此,我下一步的思路就是去研究一下Netty中Handler的回调机制,真正掌握才可开发逻辑正确的代码。

本文的最后,把Client端的代码补充完整,以便调试,

NettyNioClient

package com.coderli.nettylab.guide;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;

/**
 * @author lihongzhe 2018/8/6 22:55
 */
public class NettyNioClient {

    public static void main(String[] args) throws InterruptedException {
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            Bootstrap b = new Bootstrap();
            b.group(workerGroup);
            b.channel(NioSocketChannel.class);
            b.option(ChannelOption.SO_KEEPALIVE, true);
            b.handler(new ChannelInitializer<SocketChannel>() {
                @Override
                public void initChannel(SocketChannel ch) throws Exception {
                    ch.pipeline().addLast(new ClientHandler());
                }
            });

            ChannelFuture f = b.connect("127.0.0.1", 7060).sync(); 

            // Wait until the connection is closed.
            f.channel().closeFuture().sync();
        } finally {
            workerGroup.shutdownGracefully();
        }
    }

}

ClientHandler

package com.coderli.nettylab.guide;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

import java.util.Date;

/**
 * @author lihongzhe 2018/8/6 23:13
 */
public class ClientHandler extends ChannelInboundHandlerAdapter {
    private ByteBuf buf;

    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        System.out.println("Channel Registered, Client.");
        ctx.fireChannelRegistered();
    }

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) {
        System.out.println("Handler added.");
        buf = ctx.alloc().buffer(4);
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) {
        buf.release();
        buf = null;
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        ByteBuf m = (ByteBuf) msg;
        buf.writeBytes(m);
        m.release();

        if (buf.readableBytes() >= 4) { 
            long currentTimeMillis = (buf.readUnsignedInt() - 2208988800L) * 1000L;
            System.out.println(new Date(currentTimeMillis));
            ctx.close();
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }
}

后续的研究,我也会基于上述代码加以改造和调试。

阅读全文 »

Netty4自学笔记 (2) - Java NIO

发表于 2018-07-24

距离上一篇博文已经过去了半个多月。这期间有一周多的时间用在了准备单位举办的英语竞赛上。余下的时间沉迷于陪孩子玩耍和睡觉,日复一日。

当然,我也抽空学习了Java NIO(None-Blocking / New IO) 一些知识,现总结如下。

Java的非阻塞IO的原理是采用了操作系统的多路复用器机制,即在一个通道(channel)上,注册一个事件选择器(selector)及各种事件(读、写等),当有事件到达时,事件选择器返归对应的事件,然后可对事件进行处理,这样即可实现在单一线程上对来自不同客户的请求进行交替处理,服务端处理返回后即可处理下一事件,而不会受制于客户端的响应速度,提高了并发访问的效率。

Java NIO的样例代码如下:

服务端

package com.coderli.nettylab.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

/**
 * @author lihongzhe 2018/7/11 10:59
 */
public class NioServer {

    public static void main(String[] args) {
        try {
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            serverSocketChannel.bind(new InetSocketAddress("127.0.0.1", 7090));
            serverSocketChannel.configureBlocking(false);
            Selector selector = Selector.open();
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
            for (; ; ) {
                selector.select();
                Iterator<SelectionKey> keysItor = selector.selectedKeys().iterator();
                while (keysItor.hasNext()) {
                    SelectionKey selectionKey = keysItor.next();
                    keysItor.remove();
                    if (selectionKey.isAcceptable()) {
                        ServerSocketChannel ssChannel = (ServerSocketChannel) selectionKey.channel();
                        SocketChannel socketChannel = ssChannel.accept();
                        socketChannel.configureBlocking(false);
                        ByteBuffer buffer = ByteBuffer.allocate(17);
                        socketChannel.read(buffer);
                        System.out.println("Receive msg from client:" + new String(buffer.array()));
                        socketChannel.write(ByteBuffer.wrap(new String("Server: op_accept").getBytes()));
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}

客户端

package com.coderli.nettylab.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

/**
 * @author lihongzhe 2018/7/12 15:54
 */
public class NioClient {

    public static void main(String[] args) {
        try {
            SocketChannel socketChannel = SocketChannel.open();
            socketChannel.configureBlocking(false);
            socketChannel.connect(new InetSocketAddress("127.0.0.1", 7090));
            Selector selector = Selector.open();
            socketChannel.register(selector, SelectionKey.OP_CONNECT);
            selector.select();
            Iterator<SelectionKey> itor = selector.selectedKeys().iterator();
            while (itor.hasNext()) {
                SelectionKey key = itor.next();
                if (key.isConnectable()) {
                    System.out.println("Connectable...");
                    while (socketChannel.isConnectionPending()) {
                        socketChannel.finishConnect();
                        socketChannel.register(selector, SelectionKey.OP_READ);
                    }
                    SocketChannel channel = (SocketChannel) key.channel();
                    channel.write(ByteBuffer.wrap("I am client".getBytes()));
                }
            }
            for (; ; ) {
                selector.select();
                Iterator<SelectionKey> keyIterator = selector.selectedKeys().iterator();
                while (keyIterator.hasNext()) {
                    SelectionKey key = keyIterator.next();
                    if (key.isConnectable()) {
                        System.out.println("Connectable...");
                    }
                    if (key.isReadable()) {
                        SocketChannel channel = (SocketChannel) key.channel();
                        ByteBuffer buffer = ByteBuffer.allocate(17);
                        channel.read(buffer);
                        System.out.println("Receive msg from server:" + new String(buffer.array()));
                        keyIterator.remove();
                    }
                }
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

上述代码谈不上合理与严谨,仅是我实验中的代码,但可表述出Java NIO中的channel、select、selectionKey(事件)等基本要素,仅供参考。

对代码做一简单说明:

  1. 服务端将监听端口绑定在7090上,并在通道上注册了OP_ACCEPT事件;
  2. 客户端通过connect方法连接到服务端的该端口上,同时服务端监听到该事件,selector.select方法返回;
  3. 客户端首先监听了OP_CONNECT事件,在开始与服务端建立连接后,客户端获取到该事件并处理该事件,由于是非阻塞异步连接,因此需要通过socketChannel.isConnectionPending()来判断是否连接完成,并手动通过socketChannel.finishConnect();方法完成连接,然后注册OP_READ事件,用于监听服务端传输的信息;
  4. 客户端和服务端之间通过ByteBuffer作为载体传输数据;
  5. 客户端监听的OP_READ事件后,当服务端向channel写入数据后,客户端select到该事件,并读取信息。

对比BIO(OIO)来看,如要实现并发,BIO模式下的每一个客户端请求需要用一个线程与之对应,显然无法实现大规模并发;而NIO模式下,因为是事件驱动,一个selector可以处理所有客户端的事件,只有当有事件到达时才会返回处理,只需要启动一定数量的事件处理线程去异步处理客户端事件即可。因此,NIO模式从理论上具备应对高并发的条件。

至此,我暂不再去深究操作系统层面epoll等技术细节,带着对Java BIO、NIO的初步认识,下一步打算去了解一下使用Netty如何去创建和访问一个BIO、NIO的服务以及Netty带给我们的封装和基本的设计思想。

阅读全文 »

Netty4自学笔记 (1) - Java BIO

发表于 2018-07-06

2012年,由于项目的需要我第一次接触到了Netty,当时Netty还处于3.x版本。我用十几篇博文记录了自己自学Netty的过程,虽然内容浅薄,但没想到被各处转载,我想主要是因为当时Netty的资料确实较少的缘故。

五六年过去了,Netty早已发展到了4.x系列,好奇也好,求知也罢,我打算重学Netty,虽然严格来说,我已不是IT从业人员,但我仍希望保留对技术的热爱与追求。

学习Netty,就免不了先去了解Java中的几种通信模型。我不想先去学习很多概念,单刀直入,就先从最容易理解的BIO(阻塞I/O)学起。

阻塞I/O,顾名思义,就是服务端在接受到客户端的请求时,在当前线程下是阻塞执行的。只有当一个客户端请求关闭后,才能接受其他客户端的请求。阻塞I/O的JDK原生实现代码如下:

服务端

package com.coderli.nettylab.bio;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * @author lihongzhe 2018-06-19 11:06
 */
public class BioServer {

    public static void main(String[] args) throws IOException {
        ServerSocket socketServer = new ServerSocket();
        socketServer.bind(new InetSocketAddress("127.0.0.1", 7080)); 
        for (; ; ) {
            Socket socket = socketServer.accept();
            System.out.println("接收到新的连接请求。");
            InputStream is = socket.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(is));
            String line = reader.readLine();
            System.out.println(line);
            socket.getOutputStream().write("Hello, I'm server.".getBytes());
            socket.shutdownOutput();
        }
    }

}

客户端

package com.coderli.nettylab.bio;

import java.io.*;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketImpl;

/**
 * @author lihongzhe 2018-06-21 23:24
 */
public class BioClient {

    public static void main(String[] args) throws IOException {
        Socket socket = new Socket();
        socket.connect(new InetSocketAddress("127.0.0.1", 7080));
        OutputStream os = socket.getOutputStream();
        InputStream is = socket.getInputStream();
        os.write("Hello, I'm client.".getBytes());
        socket.shutdownOutput();
        BufferedReader br = new BufferedReader(new InputStreamReader(is));
        System.out.println(br.readLine());
        socket.close();
    }

}

简单解释一下上述代码:

  1. 服务端,通过 socketServer.bind() 绑定到指定的端口;
  2. 服务端,通过 socketServer.accept() 开启监听,等待客户端连接。当没有客户端连接时,代码阻塞在此处;
  3. 客户端,先构造一个Socket实例,然后通过socket.connect()函数连接到刚服务端绑定的端口上。此时,若成果连接,则服务端代码继续执行;
  4. 服务端,socketServer.accept() 函数返回一个Socket实例,在实例中可以得倒输入(InputStream)/输出(OutputStream)流,用于与客户端之间读取/写入数据;
  5. 由于底层依赖的协议并没有要求数据流必须一次传输完成,实际上对于要传输的数据,可多次调用 socket.getOutputStream().write()函数写入数据。因此,必须有明确的手段标明一次数据传输的结束, socket.shutdownOutput()函数的作用正是如此。

由此可见,服务端同一时刻、同一线程只能处理来自一个客户端的请求,显然这种连接模式的并发效率并不能令人满意。

我暂不深究更多的细节,接下来先去了解一下Java NIO模式的特点和开发方式。

阅读全文 »

LeetCode Implement Queue Using Stacks

发表于 2018-06-08

Problem

Implement the following operations of a queue using stacks.

push(x) -- Push element x to the back of queue.
pop() -- Removes the element from in front of queue.
peek() -- Get the front element.
empty() -- Return whether the queue is empty.

Example:

MyQueue queue = new MyQueue();

queue.push(1);
queue.push(2);  
queue.peek();  // returns 1
queue.pop();   // returns 1
queue.empty(); // returns false

Notes:

You must use only standard operations of a stack – which means only push to top, peek/pop from top, size, and is empty operations are valid. Depending on your language, stack may not be supported natively. You may simulate a stack by using a list or deque (double-ended queue), as long as you use only standard operations of a stack. You may assume that all operations are valid (for example, no pop or peek operations will be called on an empty queue).false

即用stack来实现queue

Python3

# Implement the following operations of a queue using stacks.
#
# push(x) -- Push element x to the back of queue.
# pop() -- Removes the element from in front of queue.
# peek() -- Get the front element.
# empty() -- Return whether the queue is empty.
# Example:
#
# MyQueue queue = new MyQueue();
#
# queue.push(1);
# queue.push(2);
# queue.peek();  // returns 1
# queue.pop();   // returns 1
# queue.empty(); // returns false
# Notes:
#
# You must use only standard operations of a stack -- which means only push to top, peek/pop from top, size, and is
# empty operations are valid.
# Depending on your language, stack may not be supported natively. You may simulate a stack by using a list or
# deque (double-ended queue), as long as you use only standard operations of a stack.
# You may assume that all operations are valid (for example, no pop or peek operations will be called on an empty queue).

class MyQueue:

    def __init__(self):
        """
        Initialize your data structure here.
        """
        self._data = []
        self._temp_stack = []

    def push(self, x):
        """
        Push element x to the back of queue.
        :type x: int
        :rtype: void
        """
        self._data.append(x)

    def pop(self):
        """
        Removes the element from in front of queue and returns that element.
        :rtype: int
        """
        if len(self._temp_stack) == 0:
            while len(self._data) != 0:
                self._temp_stack.append(self._data.pop())
        return self._temp_stack.pop()

    def peek(self):
        """
        Get the front element.
        :rtype: int
        """
        if len(self._temp_stack) == 0:
            while len(self._data) != 0:
                self._temp_stack.append(self._data.pop())
        return self._temp_stack[-1]

    def empty(self):
        """
        Returns whether the queue is empty.
        :rtype: bool
        """
        return len(self._data) == 0 and len(self._temp_stack) == 0

# Your MyQueue object will be instantiated and called as such:
# obj = MyQueue()
# obj.push(x)
# param_2 = obj.pop()
# param_3 = obj.peek()
# param_4 = obj.empty()

分析

无话可说……

阅读全文 »

LeetCode Power of Two

发表于 2018-06-07

Problem

Given an integer, write a function to determine if it is a power of two.

Example 1:

Input: 1
Output: true 
Explanation: 2^0 = 1

Example 2:

Input: 16
Output: true
Explanation: 2^4 = 16

Example 3:

Input: 218
Output: false

判断一个整数是否是2的幂次方

Python3

# Given an integer, write a function to determine if it is a power of two.
#
# Example 1:
#
# Input: 1
# Output: true
# Explanation: 20 = 1
# Example 2:
#
# Input: 16
# Output: true
# Explanation: 24 = 16
# Example 3:
#
# Input: 218
# Output: false

class Solution:
    def isPowerOfTwo(self, n):
        """
        :type n: int
        :rtype: bool
        """
        if n == 0:
            return False
        binary_str = bin(n)[3:]
        for c in binary_str:
            if c is not '0' and not '':
                return False
        return True

    def isPowerOfTwo_bit_operation(self, n):
        """
        :type n: int
        :rtype: bool
        """
        if n <= 0:
            return False
        while n > 0:
            if n & 1 and n != 1:
                return False
            n = n >> 1
        return True

分析

给出两种办法。一种是解析二进制的字符串。因为2的次幂都是1后面接n个0的形式的,因此判断是否有0以外的字符串即可。

另一种是利用与运算,利用的性质是一样的。个人推荐第二种思考方式。

阅读全文 »
1 … 5 6 7 … 36
LiHongZhe

LiHongZhe

onecoder's blog.

354 日志
8 分类
RSS
Creative Commons
Links
  • 酷壳
  • 煮酒品茶
  • 小弟子的网络之路
  • 图表秀-在线图表制作
© 2012 - 2023 LiHongZhe
由 Jekyll 强力驱动
主题 - NexT.Muse
本站访客数 人次 本站总访问量 次