zoukankan      html  css  js  c++  java
  • CRACKING THE CODING INTERVIEW 笔记(1)

    1. Arrays and Strings

    1.1 Hash Tables

    哈希表,简单的说就是由一个数组和一个hash函数组成实现key/value映射并且能高效的查找的数据结构。最简单的想法就是将hash(key)做为数组的下标(index)来存取。

    但是为了防止hash的冲突(collisions),数组的大小必须设置得足够大,因此上面这种简单的实现在实际中是不可取的。

    实际上,哈希表是一个固定大小的数组,数组的每个元素是一个链表(单向或双向)的头指针。每个元素被存放在hash(key)%array_length所在的链表中。如下图所示:

    另外,我们可以用二叉查找树(bst)来实现哈希表,在平衡树的基础上能保证0(logn)的查询时间, 而且相对节省空间。

    1.2 ArrayList

    ArrayList是一个可动态扩张的数组,一个典型的实现就是当ArrayList满了的时候,它会将大小扩大一倍,这个扩张的动作的时间复杂度在O(n),但是发生得很少,所以均摊下来ArrayList的读取复杂度还是O(1)。

    1.3 StringBuffer

    当考虑进行大量的字符串连接操作的时候,如果使用String中的+操作符来进行,将导致非常糟糕的性能,因为String为不可变对象,一旦被创建,就不能修改它的值。所以下面这条语句

    str1 = str1 + str2;

    等同于生成了一个新的str1对象,然后将指针指向新的 str1对象,所以经常改变内容的字符串最好不要用String对象 ,因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了以后,JVM 的 GC 就会开始工作,那速度是一定会相当慢的。

    而如果是使用StringBuffer类则结果就不一样了,每次结果都会对StringBuffer对象本身进行操作,而不是生成新的对象,再改变对象引用。StringBuffer上的主要操作是 append 和 insert 方法。append 方法始终将这些字符添加到缓冲区的末端;而 insert 方法则在指定的点添加字符。

    所以在一般情况下我们推荐使用StringBuffer,特别是字符串对象经常改变的情况下。而在某些特别情况下, String 对象的字符串拼接其实是被 JVM 解释成了StringBuffer对象的拼接,所以这些时候 String 对象的速度并不会比StringBuffer对象慢,而特别是以下的字符串对象生成中, String 效率是远要比StringBuffer快的:

    String s1 = "This is only a" + "simple" + "test";
    StringBuffer sb = new StringBuilder("This is only a").append(" simple").append("test");

     你会很惊讶的发现,生成 String S1 对象的速度简直太快了,而这个时候StringBuffer居然速度上根本一点都不占优势。其实这是 JVM 的一个把戏,在 JVM 眼里,这个

    String s1 = "This is only a" + "simple" + "test";

     其实就是: 

    String s1 = "This is only a simple test";

    所以当然不需要太多的时间了。但要注意的是,如果字符串是来自另外的 String 对象的话,速度就没那么快了,譬如:

    String S2 = "This is only a";
    String S3 = "simple";
    String S4 = "test";
    String S1 = S2 +S3 + S4;

    这时候 JVM 会规规矩矩的按照原来的方式去做。

    另外,StringBuilder是5.0新增的一个可变的字符序列。此类提供一个与StringBuffer兼容的 API,但不保证同步。该类被设计用作StringBuffer的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。如果可能,建议优先采用该类,因为在大多数实现中,它比StringBuffer要快。两者的方法基本相同。区别就在于StringBuffer是线程安全的而
    StringBuilder
    非线程安全。

    关于StringBufferStringBuilder的实现:

    StringBuffer是一个用于存放动态存放字符串数据的类,他继承自java.lang.AbstractStringBuilder这个类。 

    所谓动态存放是指:你无需考虑StringBuffer大小的问题。 
    当你利用StringBuffer的append方法向其自身添加字符串的时候,如果此时StringBuffer默认提供的空间大小不够用,
    那么它会自动扩展自身的存储空间,以保证数据能够正常的放入到StringBuffer其中。 

    我们也可以手动的设置StringBuffer的空间大小
    例如:

    StringBuffer buf = new StringBuffer(10); 

    上面的意思是指:将StringBuffer的内部容量设置为10个字符(char)大小的长度。 

    StringBuffer默认的存储空间大小是16个字符,也就是说 new StringBuffer() 就等于 new StringBuffer(16)。 
    StringBuffer的底层是利用它的父类(AbstractStringBuilder)内部的一个默认长度为16的字符数组来存放数据的。(即:char value[];) 

    每当利用 StringBuffer的append方法向其中添加一个字符串的时候StringBuffer都会调用其父类(AbstractStringBuilder)的append方法, 
    然后AbstractStringBuilder会判断其内部用于存放数据的那个char[]数组是否已经满了, 
    (1)如果没有满,就会将你传入的字符串转化为 
    字符并存入到那个字符数组中(即: str.getChars(0, len, value, count);)。 
    (2)而如果那个char[]数组已经满了,那么AbstractStringBuilder会创建一个大小为当前数组两倍的新的char[]数组。 
    然后利用System.arraycopy(value, 0, newValue, 0, count);将原始数据拷贝到这个新的数组中即可。

  • 相关阅读:
    HDU 1232 (畅通工程) 并查集经典模板题
    (POJ
    Gitlab利用Webhook实现Push代码后的jenkins自动构建
    Jenkins 配置git
    Jenkins安装及基本配置(Linux版,使用web容器 tomcat 搭建)
    Gitlab安装、汉化及使用
    ssh 免密码登录(设置后仍需输密码的原因及解决方法)
    appium1.4版本,每次运行appium时需要安装unlock,setting文件的解决方法
    jmeter完成md5加密的接口请求参数
    jmeter插件使用说明
  • 原文地址:https://www.cnblogs.com/giraffe/p/Arrays_and_Strings.html
Copyright © 2011-2022 走看看