google面试官还会告诉你这些

  递归书写方法

  数学归纳法中的数学/自然语言–程序语言(证明递归函数正确执行)

  严格定义递归函数作用,包括参数,返回值,Side-effect

  先一般,后特殊

  每次调用必须缩小问题规模

  每次问题规模缩小程度必须为1

  递归缺点

  调用堆栈Stack太深,开销大

  如果数据大,就会Stack Overflow!

  不要尝试递归改成非递归

  一般化的方法仍需要栈

  代码复杂

  不根本解决问题

  Side-effect 函数副作用。理想的状态是函数运行完没有side-effect。 比较函数执行中会修改全局的一些属性,当执行完,也要将这些全局属性还原

  链表

  

图片描述

 

  package interview.recursion;

  import java.util.ArrayList;

  import java.util.Arrays;

  import java.util.List;

  import interview.common.Node;

  public class LinkedListCreator {

  /**

  * Creates a linked list.

  *

  * @param data the data to create the list

  * @return head of the linked list. The returned linked list

  * ends with last node with getNext() == null.

  */

  publicNodecreateLinkedList(Listdata) {

  if (data.isEmpty()) {

  return null;

  }

  NodefirstNode = new Node(data.get(0));

  firstNode.setNext(

  createLinkedList(data.subList(1, data.size())));

  return firstNode;

  }

  public NodecreateLargeLinkedList(int size) {

  Nodeprev = null;

  Nodehead = null;

  for (int i = 1; i = size; i++) {

  Nodenode = new Node(i);

  if (prev != null) {

  prev.setNext(node);

  } else {

  head = node;

  }

  prev = node;

  }

  return head;

  }

  public static void main(String[] args) {

  LinkedListCreator creator = new LinkedListCreator();

  Node.printLinkedList(

  creator.createLinkedList(new ArrayList()));

  Node.printLinkedList(

  creator.createLinkedList(Arrays.asList(1)));

  Node.printLinkedList(

  creator.createLinkedList(Arrays.asList(1, 2, 3, 4, 5)));

  }

  }

  链表反转

  

图片描述

 

  package interview.recursion;

  import java.util.ArrayList;

  import java.util.Arrays;

  import interview.common.Node;

  public class LinkedListReverser {

  /**

  * Reverses a linked list.

  *

  * @param head the linked list to reverse

  * @return head of the reversed linked list

  */

  publicNodereverseLinkedList(Nodehead) {

  // size == 0 or size == 1

  if (head == null || head.getNext() == null) {

  return head;

  }

  // 第一步(对应上图)

  NodenewHead = reverseLinkedList(head.getNext());

  // 第二步

  head.getNext().setNext(head);

  // 第三步 over

  head.setNext(null);

  return newHead;

  }

  public static void main(String[] args) {

  LinkedListCreator creator = new LinkedListCreator();

  LinkedListReverser reverser = new LinkedListReverser();

  Node.printLinkedList(reverser.reverseLinkedList(

  creator.createLinkedList(new ArrayList())));

  Node.printLinkedList(reverser.reverseLinkedList(

  creator.createLinkedList(Arrays.asList(1))));

  Node.printLinkedList(reverser.reverseLinkedList(

  creator.createLinkedList(Arrays.asList(1, 2, 3, 4, 5))));

  System.out.println(Testing large data. Expect exceptions.);

  reverser.reverseLinkedList(

  creator.createLargeLinkedList(1000000));

  System.out.println(done);

  }

  }

  combinations([1,2,3,4],2)

  缩小问题规模

  选1combinations([2,3,4],1)

  不选1combinations([2,3,4],2)

  package interview.recursion;

  import java.util.ArrayList;

  import java.util.Arrays;

  import java.util.List;

  public class Combinations {

  /**

  * Generates all combinations and output them,

  * selecting n elements from data.

  */

  public void combinations(

  Listselected, Listdata, int n) {

  if (n == 0) {

  // output all selected elements

  for (Integer i : selected) {

  System.out.print(i);

  System.out.print( );

  }

  System.out.println();

  return;

  }

  if (data.isEmpty()) {

  return;

  }

  // select element 0

  selected.add(data.get(0));

  combinations(selected, data.subList(1, data.size()), n - 1);

  // un-select element 0

  selected.remove(selected.size() - 1);

  combinations(selected, data.subList(1, data.size()), n);

  }

  public static void main(String[] args) {

  Combinations comb = new Combinations();

  System.out.println(Testing normal data.);

  comb.combinations(

  new ArrayList(), Arrays.asList(1, 2, 3, 4), 2);

  System.out.println(==========);

  System.out.println(Testing empty source data.);

  comb.combinations(

  new ArrayList(), new ArrayList(), 2);

  System.out.println(==========);

  comb.combinations(

  new ArrayList(), new ArrayList(), 0);

  System.out.println(==========);

  System.out.println(Selecting 1 and 0 elements.);

  comb.combinations(

  new ArrayList(), Arrays.asList(1, 2, 3, 4), 1);

  System.out.println(==========);

  comb.combinations(

  new ArrayList(), Arrays.asList(1, 2, 3, 4), 0);

  System.out.println(==========);

  System.out.println(Testing large data);

  comb.combinations(

  new ArrayList(),

  Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10), 4);

  }

  }

  循环控制(循环不变式 loop invariant)

  

图片描述

 

  

图片描述

 

  边界控制

  列表项

  初始值

  特殊值

  null

  空字符串

  数据结构

  树的遍历

  算法复杂度

  代表最坏情况用时

  f(x)=O(g(x))asx-oo 当且仅当

  If(x)1≤Mlg(x)l for all x =xo 相当于高等数学中极限的定义

  广义的“极限”是指“无限靠近而永远不能到达”的意思。数学中的“极限”指:某一个函数中的某一个变量,此变量在变大(或者变小)的永远变化的过程中,逐渐向某一个确定的数值A不断地逼近而“永远不能够重合到A”(“永远不能够等于A,但是取等于A‘已经足够取得高精度计算结果)的过程中,此变量的变化,被人为规定为“永远靠近而不停止”、其有一个“不断地极为靠近A点的趋势”。极限是一种“变化状态”的描述。此变量永远趋近的值A叫做“极限值”(当然也可以用其他符号表示)。

  面向对象思想

  商业代码复杂性,从用户角度思考问题

  摒弃完全基于逻辑的思维

  类与对象

  类的成员变量对象状态

  类的成员函数对象行为

  类的静态变量

  类的静态函数

  没有this引用,静态变量全局唯一—份

  普通函数可以引用静态变量、函数

  对象上引用静态变量、函数会产生编译器警告

  静态函数引用普通成员变量、函数会编译错误

  

图片描述

 

  

图片描述

 

  类的特殊函数

  构造函数

  equals

  hashCode

  toString

  a.equals(b)说明a.hashCode)==b.hashCode) 必要条件

  接口与实现

  

图片描述

 

  与类相比

  由编译器强制的一个模块间协作的合约(Contract)

  无成员变量

  成员函数只有申明不能有实现

  接口的申明

  Java:interface BankEndPoint{……

  C++:一个全部是纯虚函数的类

  Python/大部分动态语言:依靠注释申明

  接口和抽象类有什么不同?

  从实现角度看

  抽象类可以有成员变量

  抽象类可以有部分实现

  抽象类不可以多重继承,接口可以

  接口强调合约

  强制协作双方无法犯错(编译器)

  但是抽象类提供公共的实现

  

图片描述

 

  继承与封装

  不可变对象 Immutable Objects

  可以引用传递,可以缓存

  线程安全

  final 关键字

  类申明类不可以被继承

  函数申明函数不可以在派生类中重写

  变量申明变量不可以指向其它对象

  static final变量用于定义常量,名称一般大写

  final关键字无法保证不可变性

  从接口定义,类的实现上保证不可变性

  Collections.unmodifiableXXX

  泛型

  c++虚函数表

  

图片描述

 

  void dispatch_work(Employee* p){

  p-doWork();

  dispatch_ work(manager);

  

图片描述

 

  设计模式(解耦和)

  设计模式当初的提出就是因为GOF(Erich Gamma,Richard Helm,Ralph Johnson和John Vlissides)的博士论文(这才是真正的程序员)

  

图片描述

 

  再谈Singleton(单例模式)

  确保全局至多只有一个对象

  用于:构造缓慢的对象,需要统一管理的资源

  缺点:很多全局状态,线程安全性

  双重锁 Double checked locking

  第一次check全局对象是不是null,不是null直接拿来用,如果是null,锁住,再check一次(防止其他人在这个空挡创建)

  作为Java类的静态变量(全局只有一份,不过程序员初始化就要创建这个静态变量,所以也就增加了初始化的时间(如果是比较缓慢的对象))

  使用框架提供的能力

  依赖注入

  变继承关系为组合关系(状态模式State)

  描述is-a关系

  不要用继承关系来实现复用

  状态逻辑和动作实现没有分离。在很多的系统实现中,动作的实现代码直接写在状态的逻辑当中。这带来的后果就是系统的扩展性和维护得不到保证。

  使用设计模式来实现复用

  

图片描述

 

  

图片描述

 

  Decotator装饰器模式

  interface Runnable{

  void run);

  如何实现LoggingRunnable,TransactionalRunnable.…

  

图片描述

 

  

图片描述

 

  对象如何创建

  使用new来创建的缺点

  编译时必须决定创建哪个类的对象

  参数意义不明确

  Abstract Factory Pattern 抽象工厂

  task=new Logging Task(new Coding Task);

  task=taskFactory.createCodingTask); (好)

  Builder Pattern 生成器

  解决参数意义不明确的问题

  不可变对象往往配合Builder使用

  employee=new Employee(

  oldEmployee.getName),15000);

  employee=Employee.fromExisting(oldEmployee)

  .withSalary(15000)

  .build();

  Beautiful Numbers

  1,11,111…是beautiful的

  32进制11

  133进制111(选位数多的)

  133+1*3+1=13

  13%3=1,13/3=4

  4%3=1,4/3=1

  1%3=1,1/3=0

  1312进制11

  Nr进制111…1(k个) 求大数据集思路

  N=r(k-1)+r(k-2)+.…+r+1

  N=(1-r^k)/(1-r)

  假设N能转化成k个1组成的Beautiful Number

  那么这个Beautiful Number是几进制?r=?

  因为k最多是64个(最低两位),但是r最多就太大了

  O(nlogn) 10*8 ~= 1s

  package interview.google;

  import java.io.BufferedReader;

  import java.io.InputStreamReader;

  import java.util.Scanner;

  public class BeautifulNumber {

  public static void main(String[] args) {

  Scanner in = new Scanner(

  new BufferedReader(new InputStreamReader(System.in)));

  int cases = in.nextInt();

  for (int i = 1; i = cases; ++i) {

  long n = in.nextLong();

  System.out.println(Case # + i + :

  + beautiful(n));

  }

  }

  private static long beautiful(long n) {

  for (long radix = 2; radix n; radix++) {

  if (isBeautiful(n, radix)) {

  return radix;

  }

  }

  throw new IllegalStateException(Should not reach here.);

  }

  private static boolean isBeautiful(long n, long radix) {

  while (n 0) {

  if (n % radix != 1) {

  return false;

  }

  n /= radix;

  }

  return true;

  }

  }

  O(logn*logn*logn) 64*64*64

  package interview.google;

  import java.io.BufferedReader;

  import java.io.InputStreamReader;

  import java.util.Scanner;

  public class BeautifulNumberLarge {

  public static void main(String[] args) {

  Scanner in = new Scanner(

  new BufferedReader(new InputStreamReader(System.in)));

  int cases = in.nextInt();

  for (int i = 1; i = cases; ++i) {

  long n = in.nextLong();

  System.out.println(Case # + i + :

  + beautiful(n));

  }

  }

  private static long beautiful(long n) {

  for (int bits = 64; bits = 2; bits--) {

  long radix = getRadix(n, bits);

  if (radix != -1) {

  return radix;

  }

  }

  throw new IllegalStateException(Should not reach here.);

  }

  /**

  * Gets radix so that n is 111...1 (bits 1 in total) in that

  * radix.

  *

  * @return the radix. -1 if there's no such radix.

  */

  private static long getRadix(long n, int bits) {

  long minRadix = 2;

  long maxRadix = n;

  while (minRadix maxRadix) {

  // 二分查找法

  long m = minRadix + (maxRadix - minRadix) / 2;

  long t = convert(m, bits);

  if (t == n) {

  return m;

  } else if (t n) {

  minRadix = m + 1;

  } else {

  maxRadix = m;

  }

  }

  return -1;

  }

  /**

  * Returns the value of 111...1 (bits 1 in total) in radix.

  * 等比数列求和

  */

  private static long convert(long radix, int bits) {

  long component = 1;

  long sum = 0;

  for (int i = 0; i bits; i++) {

  if (Long.MAX_VALUE - sum component) {

  sum = Long.MAX_VALUE;

  } else {

  sum += component;

  }

  // 防止内存溢出

  if (Long.MAX_VALUE / component radix) {

  component = Long.MAX_VALUE;

  } else {

  component *= radix;

  }

  }

  return sum;

  }

  }