2015.02.最新面试题(2)

Q1: Given an integer array, adjust each integers so that the difference of every
adjcent integers are not greater than a given number target.

If the array before adjustment is A, the array after adjustment is B, you 
should minimize the sum of |A[i]-B[i]| 

例子
Given [1,4,2,3] and target=1, one of the solutions is [2,3,2,3], the 

adjustment cost is 2 and it's minimal. Return 2.


分析:用DP可解。先找到输入array A的最小值min和最大值max。

然后建一个二维数组cost[i][j],其中0<= i < len(A), 0<= j < max-min+1 

递归公式是 cost[i][j] = min(cost[i-1][j-target], ..., cost[i-1][j+target]) + abs(A[j] - (j+min))

python实现如下:

def get_min_cost(A, target):
    if len(A) < 2:
        return 0
        
    min_val = min(A)
    max_val = max(A)
    
    clen = max_val+1-min_val
    B = [-1 for i in range(clen)]
    table = [B[:] for c in A]

    for j in range(clen):
        table[0][j] = abs(A[0]-(j+min_val)) 

    for i in range(1, len(A)):
        for j in range(clen):            
            start = max(j-target, 0)
            end = min(j+target+1, clen)
            table[i][j] = min(table[i-1][start:end]) + abs(A[i]-(j+min_val))
                
    return min(table[-1])


Q2. 有一个长为L的木料需要割开,割的位置在一个数组里A[1...N],从一个地方切开的cost是当前所
切木料的长度,按不同的顺序切割,得到的total cost是不一样的,问怎么切cost最小。

分析:这是一道老题,用DP,递归公式如下:

定义从i位置到j位置(i<j)的木料段的cost是 cost[i][j] = min(cost[i][k]+cost[k][j]) + (A[j]-A[i]),其中k = i+1....j-1 。

Python 实现如下:

def get_min_cost(A, N):
    if not A:
        return 0
    elif len(A) == 1: 
        return N
    A.sort()    
    A.insert(0, 0)
    A.append(N)

    cost = {}

    for i in range(len(A)):
        if(i+1<len(A)): cost[(i,i+1)] = 0

    for m in range(2, len(A)):
        i = 0
        for j in range(m, len(A)):
            cost[(i, j)] = N*len(A)
            for k in range(i+1, j):
                cost[(i, j)] = min(cost[(i, j)], cost[(i,k)] + cost[(k, j)] + (A[j] - A[i]))
            i+=1
                
    return cost[(0, len(A)-1)]


Q3. 在一个二维平面,原点(1,1), 跳跃规则(a,b) to (a+b,b) or (a,b+a). 给任意一个坐

标(m,n), 返回从原点到达的最小步数

分析:

使用 辗转相除法,同样的方法还适用于 求两个数的最大公约数,具体参见 http://en.wikipedia.org/wiki/Euclidean_algorithm 。

Python 实现如下:

def find_num_steps(A):
    if A[0] <= 0 or A[1] <= 0:
        return -1
    
    small_val = min(A[0], A[1])
    large_val = max(A[0], A[1])

    nsteps = 0
    while small_val != 1:
        nsteps = large_val//small_val;
        temp = small_val
        small_val = large_val % small_val
        large_val = temp
        if small_val == 0: return -1

    nsteps += large_val//small_val -1

    return nsteps


Q4. 1. You have a number of meetings (with their start and end times). You need 
to schedule them using the minimum number of rooms. Return the list of 
meetings in every room. 

分析:假设每个会议用[start, end]的interval表示,这道题有两个解法:

方法1:用贪心算法,把所有会议按开始时间排序,然后插入房间,如果当前已经在使用的房间能够安排,就插入该会议。否则,就要开新房间。

这个解法的时间复杂度是O(N^2)。

python 实现如下:

def arrangeRoom( A):
        A.sort(key = lambda x:x[0])
        res = [[A[0]]]
        for i in range(1,len(A)):
                for j in range(len(res)):
                    if res[j][-1][-1] <= A[i][0]:
                        res[j].append(A[i])
                        break
                    if j == len(res) - 1:
                        res.append([A[i]])
        return res


方法2:在方法1的基础上还可以优化,把安排的房间按最后会议的结束时间,建个最小堆。每次对于新的会议,只要和堆顶房间比较。如果不冲突,就加入该房间,否则,只能开新房间了。加入后,维护最小堆。时间复杂度是O(N logN),比方法1要好一点。

C++ 实现如下:

struct Interval{
  int start;
  int end;
  Interval(int s, int e) : start(s), end(e) {}
};

class LessStart{
public:
  bool operator()(const Interval& a, const Interval& b) const{
    return a.start < b.start;
  }
};

class GreaterEnd{
public:
  bool operator()(const vector<Interval>& a, const vector<Interval>& b) const{
    return a.back().end > b.back().end;
  }
};

vector<vector<Interval> > arrangeRoom(vector<Interval> meetings){
  vector<vector<Interval> > result;
  if(meetings.empty()) return result;

  sort(meetings.begin(), meetings.end(), LessStart());
  
  result.push_back(vector<Interval>(1, meetings[0]));

  GreaterEnd comp;
  
  for(int i=1; i<meetings.size(); ++i){        
    if(meetings[i].start >= result.front().back().end){
      pop_heap(result.begin(), result.end(), comp);      
      result.back().push_back(meetings[i]);
      push_heap(result.begin(), result.end(), comp);
    }
    else{
      result.push_back(vector<Interval>(1, meetings[i]));
      push_heap(result.begin(), result.end(), comp);
    }            
  }
  return result;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值