《算法导论》第四章-第1节_练习(参考答案)

来源:互联网 发布:excel函数重复数据 编辑:程序博客网 时间:2024/05/18 02:47

算法导论(第三版)参考答案:练习4.1-1,练习4.1-2,练习4.1-3,练习4.1-4,练习4.1-5

Exercise 4.1-1

What does FIND-MAXIMUM-SUBARRAY return when all elements of A are negative?

返回 A 中最大的一个负数。

Exercise 4.1-2

Write pseudocode for the brute-force method of solving the maximum-subarray problem. Your procedure should run in Θ(n2) time.

FIND-MAX-SUBARRAY(A, low, high)  left = 0  right = 0  sum = -∞  for i = low to high      current-sum = 0      for j = i to high      current-sum += A[j]      if sum < current-sum        sum = current-sum        left = i        right = j  return (left, right, sum)

Exercise 4.1-3

Implement both the brute-force and recursive algorithms for the maximum-subarray problem on your own computer. What problem size n0 gives the crossover point at which the recursive algorithm beats the brute-force algorithm? Then, change the base case of the recursive algorithm to use the brute-force algorithm whenever the problem size is less than n0. Does that change the crossover point?

C code

#include <limits.h>#define CROSSOVER_POINT 37// A struct to represent the tupletypedef struct {    unsigned left;    unsigned right;    int sum;} max_subarray;// The brute force approachmax_subarray find_maximum_subarray_brute(int A[], unsigned low, unsigned high) {    max_subarray result = {0, 0, INT_MIN};    for (int i = low; i < high; i++) {        int current_sum = 0;        for (int j = i; j < high; j++) {            current_sum += A[j];            if (result.sum < current_sum) {                result.left = i;                result.right = j + 1;                result.sum = current_sum;            }        }    }    return result;}// The divide-and-conquer solutionmax_subarray find_max_crossing_subarray(int A[], unsigned low, unsigned mid, unsigned high) {    max_subarray result = {-1, -1, 0};    int sum = 0,        left_sum = INT_MIN,        right_sum = INT_MIN;    for (int i = mid - 1; i >= (int) low; i--) {        sum += A[i];        if (sum > left_sum) {            left_sum = sum;            result.left = i;        }    }    sum = 0;    for (int j = mid; j < high; j++) {        sum += A[j];        if (sum > right_sum) {            right_sum = sum;            result.right = j + 1;        }    }    result.sum = left_sum + right_sum;    return result;}max_subarray find_maximum_subarray(int A[], unsigned low, unsigned high) {    if (high == low + 1) {        max_subarray result = {low, high, A[low]};        return result;    } else {        unsigned mid = (low + high) / 2;        max_subarray left = find_maximum_subarray(A, low, mid);        max_subarray right = find_maximum_subarray(A, mid, high);        max_subarray cross = find_max_crossing_subarray(A, low, mid, high);        if (left.sum >= right.sum && left.sum >= cross.sum) {            return left;        } else if (right.sum >= left.sum && right.sum >= cross.sum) {            return right;        } else {            return cross;        }    }}// The mixed algorithmmax_subarray find_maximum_subarray_mixed(int A[], unsigned low, unsigned high) {    if (high - low < CROSSOVER_POINT) {        return find_maximum_subarray_brute(A, low, high);    } else {        unsigned mid = (low + high) / 2;        max_subarray left = find_maximum_subarray_mixed(A, low, mid);        max_subarray right = find_maximum_subarray_mixed(A, mid, high);        max_subarray cross = find_max_crossing_subarray(A, low, mid, high);        if (left.sum >= right.sum && left.sum >= cross.sum) {            return left;        } else if (right.sum >= left.sum && right.sum >= cross.sum) {            return right;        } else {            return cross;        }    }}

Exercise 4.1-4

Suppose we change the definition of the maximum-subarray problem to allow the result to be an empty subarray, where the sum of the values of an empty subarray is 0. How would you change any of the algorithms that do not allow empty subarrays to permit an empty subarray to be the result?

原代码中加入,最大子数组为负数情况的判断。

C code

#include <limits.h>typedef struct {    unsigned left;    unsigned right;    int sum;} max_subarray;max_subarray find_max_crossing_subarray(int A[], unsigned low, unsigned mid, unsigned high) {    max_subarray result = {mid + 1, mid, 0};    int sum = 0,        left_sum = INT_MIN,        right_sum = INT_MIN;    for (int i = mid - 1; i >= (int) low; i--) {        sum += A[i];        if (sum > left_sum) {            left_sum = sum;            result.left = i;        }    }    sum = 0;    for (int j = mid; j < high; j++) {        sum += A[j];        if (sum > right_sum) {            right_sum = sum;            result.right = j + 1;        }    }    if (left_sum + right_sum < 0) {        max_subarray empty = { mid, mid, 0 };        return empty;    } else {        result.sum = left_sum + right_sum;        return result;    }}max_subarray find_maximum_subarray(int A[], unsigned low, unsigned high) {    if (high == low + 1) {        if (A[low] < 0) {            max_subarray empty = {low, low, 0};            return empty;        } else {            max_subarray result = {low, high, A[low]};            return result;        }    } else {        unsigned mid = (low + high) / 2;        max_subarray left = find_maximum_subarray(A, low, mid);        max_subarray right = find_maximum_subarray(A, mid, high);        max_subarray cross = find_max_crossing_subarray(A, low, mid, high);        if (left.sum >= right.sum && left.sum >= cross.sum) {            return left;        } else if (right.sum >= left.sum && right.sum >= cross.sum) {            return right;        } else {            return cross;        }    }}

Exercise 4.1-5

使用如下思想为最大子数组问题设计一个非递归的、线性时间的算法。从数组的左边界开始,由左至右处理,记录到目前为止已经处理过的最大子数组。若已知A[1..j]的最大子数组,基于如下性质将解扩展为A[1..j+1]的最大子数组:A[1..j+1]的最大子数组要么是A[1..j]的最大子数组,要么是某个子数组A[i..j+1](1ij+1)。在已知A[1..j]的最大子数组的情况下,可以在线性时间内找出形如A[i..j+1]的最大子数组。

(挺有意思的)

思想: A[1..j+1] 的最大子数组,可以由 A[1..j] 的最大子数组和 A[i..j+1](1ij+1) 子数组确定。(题目给的提示也许有点隐晦。直白点说就是:在求 A[1..j+1] 的最大子数组时,要求两个量:A[1..j] 的最大子数组,和以 j+1 结尾的最大子数组。两者作比较,得出结果。

函数find_maximum_subarray02,可以很好的说明这一切。current结构体中保存着最大的A[i..j+1]result结构体中保存着A[1..j] 的最大子数组。

C code

typedef struct {    unsigned left;    unsigned right;    int sum;} max_subarray;max_subarray find_maximum_subarray(int A[], unsigned low, unsigned high) {    max_subarray suffixes[high - low];    suffixes[0].left = low;    suffixes[0].right = low + 1;    suffixes[0].sum = A[low];    for (int i = low + 1; i < high; i++) {        if (suffixes[i - 1].sum < 0) {            suffixes[i].left = i;            suffixes[i].right = i + 1;            suffixes[i].sum = A[i];        } else {            max_subarray *previous = &suffixes[i - 1];            suffixes[i].left = previous->left;            suffixes[i].right = i + 1;            suffixes[i].sum = previous->sum + A[i];        }    }    max_subarray *max = &suffixes[0];    for (int i = low + 1; i < high; i++) {        if (max->sum < suffixes[i].sum) {            max = &suffixes[i];        }    }    return *max;}max_subarray find_maximum_subarray02(int A[], unsigned low, unsigned high) {    max_subarray result = {0, 0, INT_MIN};    max_subarray current = {low, low + 1, A[p]};    for (int i = low + 1; i < high; i++) {      if (current.sum <= 0) {        current.sum = A[i];        current.left = i;        current.right = i + 1;      }      else {        current.sum += A[i];        current.right = i + 1;      }      if (current.sum > result.sum) {        result.sum = current.sum;        result.left = current.left;        result.right = result.right;      }    return result;}
阅读全文
0 0