[关闭]
@rg070836rg 2015-10-09T00:11:37.000000Z 字数 5730 阅读 1791

算法概论作业9.21

算法概论作业


2.14

  1. 给定一个含有n个元素的数组,注意到数组中的某些元素是重复的,即这些元素在数组中出现不止一次。给出一种算法,以Onlogn)时间移除掉数组中的所有重复元素。

思路1:

  1. 先采用nlogn级别的排序算法,再线性扫描,得到结果。
  1. package homework_chen;
  2. /**
  3. * 文 件 名 : test214.java
  4. * 创 建 人: chen19130216
  5. * 日 期: 2015年9月21日
  6. * 描 述: 算法概论2.14题目源码
  7. */
  8. public class test214 {
  9. /**
  10. * @param args
  11. */
  12. public static void main(String[] args) {
  13. // TODO Auto-generated method stub
  14. int[] r = { 8, 6, 8, 0, 4, 2, 6, 8, 3, 2, 6, 2, 1, 2, 5, 8, 0, 6, 3, 1,
  15. 2, 3, 5, 7, 9, 5, 8, 4, 8, 5, 7, 5, 6, 6, 3, 5, };
  16. System.out.println("排序前:");
  17. printarray(r);
  18. System.out.println("\n排序后");
  19. Merge_sort(r, 0, r.length - 1);
  20. printarray(r);
  21. removerepeat(r);
  22. }
  23. public static void printarray(int[] r) {
  24. for (int key : r)
  25. System.out.print(key + " ");
  26. }
  27. /**
  28. * @param int []r 要求在线性时间内删除有序序列的重复元素
  29. */
  30. public static void removerepeat(int[] r) {
  31. int[] tmp = new int[r.length];// 大小定义比较麻烦?不知道怎么定义大小?C++可以通过传递数组长度来约束,难道java也需要么?
  32. int k = 0;
  33. int t = Integer.MIN_VALUE;
  34. for (int i = 0; i < r.length; i++) {// 当不一样就加进去,前提是有序序列
  35. if (r[i] != t) {
  36. tmp[k++] = r[i];
  37. t = r[i];
  38. }
  39. }
  40. System.out.println("\n删除后:");// 输出结果,有必要可以在重建大小为k的数组,重新赋值并传出去
  41. for (int i = 0; i < k; i++)
  42. System.out.print(tmp[i] + " ");
  43. }
  44. /**
  45. * @param int []r int start int mid int end 合并两段有序数组
  46. * 在调用时开辟新空间,归并,最后赋值回来,java自带gc,无须回收
  47. */
  48. public static void merge(int[] r, int start, int mid, int end) {
  49. int[] tmp = new int[end - start + 1];// 创建临时空间
  50. int k1 = start;// 记录第一有序序列的起始位置,
  51. int k2 = mid + 1;// 记录第一有序序列的起始位置,
  52. int k3 = 0;// 定义临时空间的起始位置
  53. while (k1 <= mid && k2 <= end) {// 当序列未到结尾时,归并
  54. if (r[k1] <= r[k2])// 若果第一个序列的值小于等于第二个,则把其存进临时数组
  55. tmp[k3++] = r[k1++];
  56. else
  57. tmp[k3++] = r[k2++];
  58. }
  59. // 当不满足while条件时,退出循环,此时将剩下的附在后面
  60. while (k1 <= mid)
  61. tmp[k3++] = r[k1++];
  62. while (k2 <= end)
  63. tmp[k3++] = r[k2++];
  64. // 全部完毕之后,将tmp回写到r数组中
  65. for (int i = 0; i < tmp.length; i++) {
  66. r[start++] = tmp[i];
  67. }
  68. }
  69. /**
  70. * @param int []r int start int end 归并排序数组 当start < end 分割 分割完毕之后,相邻的合并
  71. */
  72. public static void Merge_sort(int[] r, int start, int end) {
  73. if (start < end) {
  74. int mid = (start + end) / 2;
  75. Merge_sort(r, start, mid);
  76. Merge_sort(r, mid + 1, end);
  77. merge(r, start, mid, end);
  78. }
  79. }
  80. }

思路2:

  1. 线性下找到数组的最大值,最小值,若相差距离可以接受,则此方法效率不错。然后建立hash数组,扫描r数组,若flag位置的值为false,则改为true,否则不变,最后再顺序扫描一遍hash数组,输出结果。
  2. 此方法为On)线性级别,不符合题目的要求,但优于题目的要求。
  3. 但适用条件为密集数组,若前后跨距太大,则得不偿失
  1. package homework_chen;
  2. /**
  3. * 文 件 名 : test214.java
  4. * 创 建 人: chen19130216
  5. * 日 期: 2015年9月22日
  6. * 描 述: 算法概论2.14题目源码new
  7. */
  8. public class test214new {
  9. private static int max = Integer.MAX_VALUE;
  10. private static int min = Integer.MIN_VALUE;
  11. /**
  12. * @param args
  13. */
  14. public static void main(String[] args) {
  15. // TODO Auto-generated method stub
  16. int[] r = { 8, 6, 8, 0, 4, 2, 6, 8, 3, 2, 6, 2, 1, 2, 5, 8,
  17. 0, 6, 3, 1, 2, 3, 5, 7, 9, 5, 8, 4, 8, 5, 7, 5, 6, 6, 3, 5, };
  18. fd_max_min(r);
  19. removerepeat(r, max, min);
  20. }
  21. /**
  22. * @param int []r 找出r数组中的最大值,最小值,并赋值给全局变量
  23. */
  24. public static void fd_max_min(int[] r) {
  25. for (int i = 0; i < r.length; i++) {
  26. if (r[i] > min)
  27. min = r[i];
  28. if (r[i] < max)
  29. max = r[i];
  30. }
  31. int t = min;
  32. min = max;
  33. max = t;// 交换
  34. }
  35. /**
  36. * @param int []r 打印数组
  37. */
  38. public static void printarray(int[] r) {
  39. for (int key : r)
  40. System.out.print(key + " ");
  41. }
  42. /**
  43. *
  44. * @param r
  45. * @param max
  46. * @param min
  47. * 用hash数组判定是否存在
  48. */
  49. public static void removerepeat(int[] r, int max, int min) {
  50. int number = max - min + 1;
  51. boolean[] flag = new boolean[number];// 初始化为false
  52. for (int i = 0; i < r.length; i++) {
  53. int t = r[i] - min;
  54. if (flag[t] == false) {
  55. flag[t] = true;
  56. }
  57. }
  58. for (int i = 0; i < flag.length; i++) {
  59. if (flag[i] == true) {
  60. System.out.print((i + min)+" ");
  61. }
  62. }
  63. }
  64. }

2.16

  1. 给定一个无穷数组A[·],其中前N个元素都是整数,且已排好序,剩余元素均为∞。n的值未知.给出一个算法,以一个整数x为输入,以O(logn)时间找到数组中的一个位置,并满足其上的元素为x.

思路:

从a[1]开始,依次访问a[2],a[4],a[8],依次类推,访问至a[2i],发现a[2i*2]为∞,这个花费的时间代价为O(logn)
设k小于i+1, x必定在a[2k]至a[2k*2]之间
对这个区间进行二分搜索,定位即可,若搜索到,返回位置,若搜索不到,返回-1.

  1. package homework_chen;
  2. /**
  3. * 文 件 名 : test216.java
  4. * 创 建 人: chen19130216
  5. * 日 期: 2015年9月22日
  6. * 描 述: 算法概论2.16题目源码
  7. */
  8. public class test216 {
  9. /**
  10. * @param args
  11. * 从a[1]开始,依次访问a[2],a[4],a[8], 依次类推,访问至a[2^i],发现a[2^(i+1)]为∞,
  12. * 这个花费的时间代价为O(logn) 设k小于i+1, x必定在a[2^k]至a[2^(k+1)]之间
  13. * 对这个区间进行二分搜索, 定位即可,若搜索到,返回位置,若搜索不到,返回-1.
  14. */
  15. public static void main(String[] args) {
  16. // TODO Auto-generated method stub
  17. int[] r = { 1, 2, 5, 9, 11, 15, 17, 19, 23, 27, 29, 32, 37, 41, 45, 49,
  18. 54, 57, 59 };
  19. int x = 60;
  20. int index = solution(r, x);
  21. System.out.println("index:" + index);
  22. }
  23. /**
  24. * @param r
  25. * @param x
  26. * @return index 存在返回下标,不存在返回-1
  27. */
  28. private static int solution(int[] r, int x) {
  29. int left = 1;
  30. int right = 1;
  31. // 定位x的位置
  32. try {
  33. while (r[left] < x) {// 当x大于左界值,left翻倍
  34. left *= 2;
  35. }// 此时,数组未越界,将其作为右边界
  36. } catch (ArrayIndexOutOfBoundsException e) {
  37. } finally {
  38. right = left;// 此时left已经越界,将其作为右边界
  39. left = right / 2;
  40. System.out.println(left + " " + right);
  41. }
  42. int index = binSearch(r, left, right, x);
  43. return index;
  44. }
  45. /**
  46. * @param r
  47. * @param left
  48. * @param right
  49. * @param x
  50. * @return
  51. * 二分查找,存在返回index,不存在返回-1
  52. */
  53. private static int binSearch(int[] r, int left, int right, int x) {
  54. while (left <= right) {
  55. int mid = (left + right) / 2;
  56. try {
  57. if (x < r[mid]) {
  58. right = mid - 1;
  59. } else if (x > r[mid]) {
  60. left = mid + 1;
  61. } else if (x == r[mid]) {
  62. return mid;
  63. }
  64. } catch (ArrayIndexOutOfBoundsException e) {
  65. right = mid - 1;
  66. }
  67. }
  68. return -1;
  69. }
  70. }

2.23

  1. 如果一个数组A[1,...,n]中总数超过半数的元素都相同时,该数组被称为含有一个主元素,给定一个数组,设计一个有效算法,确定该数组中是否含有一个主元素,如果有,找出这个元素。需注意的是,该数组的元素之间可能不存在顺序——即不能进行”A[i]<A[j]”的判断,但是可以进行是否相等的判断。

思路:

  1. 整体采用分治法
  2. 当分到只有一个元素时,必定是主元素
  3. 对于连续的两段,取得左半边的主元素,取得右半边的主元素
  4. 如果左右两边一样,必定为主元素
  5. 否则线性扫描,统计次数,找到主元素,若没有返回null
  1. package homework_chen;
  2. /**
  3. * 文 件 名 : test223a.java
  4. * 创 建 人: chen19130216
  5. * 日 期: 2015年9月22日
  6. * 描 述: 算法概论2.23题目源码
  7. */
  8. public class test223a {
  9. /**
  10. * @param args
  11. */
  12. public static void main(String[] args) {
  13. // TODO Auto-generated method stub
  14. int[] r = { 1, 1, 2, 2, 2, 3, 3, 3 };
  15. Integer majority = getmajority(r, 0, r.length - 1);
  16. System.out.println("主元素为:" + majority);
  17. }
  18. /**
  19. * 求数组的主元素
  20. * @param r
  21. * @param start
  22. * @param end
  23. * @return
  24. */
  25. private static Integer getmajority(int[] r, int start, int end) {
  26. if (start == end) {// 只有一个元素时,必定是主元素
  27. return r[start];
  28. }
  29. int mid = (start + end) / 2;
  30. Integer majority0 = getmajority(r, start, mid);// 取得左半边的主元素
  31. Integer majority1 = getmajority(r, mid + 1, end);// 取得右半边的主元素
  32. if (majority0 == majority1) {// 如果左右两边一样,必定为主元素
  33. return majority0;
  34. }
  35. Integer majority = traverseAndFind(r, majority0, majority1, start, end);// 综合两边主元素判定综合主元素
  36. return majority;
  37. }
  38. /**
  39. * 本方法用于返回相邻两段的主元素,若不存在,返回null
  40. * @param r
  41. * @param majority0
  42. * @param majority1
  43. * @param start
  44. * @param end
  45. * @return
  46. */
  47. private static Integer traverseAndFind(int[] r, Integer majority0,
  48. Integer majority1, int start, int end) {
  49. int halfRate = (end - start + 1) / 2;//测定程序中的半数
  50. int fre0 = 0;//统计次数1
  51. int fre1 = 0;//统计次数2
  52. for (int i = start; i <= end; i++) {
  53. if (majority0 != null && r[i] == majority0)
  54. fre0++;
  55. if (majority1 != null && r[i] == majority1)
  56. fre1++;
  57. }
  58. if (fre0 > halfRate)//超过半数,满足主元素条件返回
  59. return majority0;
  60. if (fre1 > halfRate)
  61. return majority1;
  62. return null;//无主元素,返回空指针
  63. }
  64. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注