1. /*
  2. * 给定一个数组arr,长度为N,arr中的值不是0就是1
  3. * arr[i]表示第i栈灯的状态,0代表灭灯,1代表亮灯
  4. * 每一栈灯都有开关,但是按下i号灯的开关,会同时改变i-1、i、i+1栈灯的状态
  5. * 问题一:
  6. * 如果N栈灯排成一条直线,请问最少按下多少次开关,能让灯都亮起来
  7. * 排成一条直线说明:
  8. * i为中间位置时,i号灯的开关能影响i-1、i和i+1
  9. * 0号灯的开关只能影响0和1位置的灯
  10. * N-1号灯的开关只能影响N-2和N-1位置的灯
  11. *
  12. * */

暴力版本

  1. public static int noLoopRight(int[] arr) {
  2. if (arr == null || arr.length == 0) {
  3. return 0;
  4. }
  5. if (arr.length == 1) {
  6. return arr[0] == 1 ? 0 : 1;
  7. }
  8. if (arr.length == 2) {
  9. return arr[0] != arr[1] ? Integer.MAX_VALUE : (arr[0] ^ 1);
  10. }
  11. return f1(arr, 0);
  12. }
  13. // arr[0...i-1]的灯,不需要管
  14. // arr[i......]的灯上,按开关
  15. // 1) i位置的开关,不改变,走一个分支
  16. // 2) i位置的开关,改变,走一个分支
  17. private static int f1(int[] arr, int i) {
  18. if (i == arr.length) {
  19. return valid(arr) ? 0 : Integer.MAX_VALUE;
  20. }
  21. // 决定,在i位置,不改变开关
  22. int p1 = f1(arr, i + 1);
  23. // 决定,在i位置,改变开关
  24. change1(arr, i);
  25. int p2 = f1(arr, i + 1);
  26. change1(arr, i);
  27. p2 = (p2 == Integer.MAX_VALUE) ? p2 : p2 + 1;
  28. return Math.min(p1, p2);
  29. }
  30. private static void change1(int[] arr, int i) {
  31. if (i == 0) {
  32. arr[0] ^= 1;
  33. arr[1] ^= 1;
  34. } else if (i == arr.length - 1) {
  35. arr[i - 1] ^= 1;
  36. arr[i] ^= 1;
  37. } else {
  38. arr[i - 1] ^= 1;
  39. arr[i] ^= 1;
  40. arr[i + 1] ^= 1;
  41. }
  42. }
  43. private static boolean valid(int[] arr) {
  44. for (int i = 0; i < arr.length; i++) {
  45. if (arr[i] == 0) {
  46. return false;
  47. }
  48. }
  49. return true;
  50. }

优良递归版本

  • 这个递归函数在前态做决定

image.png
!image.png

  1. public static int noLoopMinStep1(int[] arr) {
  2. if (arr == null || arr.length == 0) {
  3. return 0;
  4. }
  5. if (arr.length == 1) {
  6. return arr[0] == 1 ? 0 : 1;
  7. }
  8. if (arr.length == 2) {
  9. return arr[0] != arr[1] ? Integer.MAX_VALUE : (arr[0] ^ 1);
  10. }
  11. //不改变0位置的状态
  12. int p1 = process1(arr, 2, arr[0], arr[1]);
  13. //改变0位置的状态
  14. int p2 = process1(arr, 2, arr[0] ^ 1, arr[1] ^ 1);
  15. if (p2 != Integer.MAX_VALUE) {
  16. p2++;
  17. }
  18. return Math.min(p1, p2);
  19. }
  20. // index : 来到的位置,不能在这个位置上做改变!
  21. // pre:前一个位置的状态,这个是要改变的!
  22. // prepre:前前状态
  23. public static int process1(int[] arr, int index, int prepre, int pre) {
  24. if (index == arr.length) { //pre压中最后一盏灯
  25. return prepre != pre ? Integer.MAX_VALUE : (pre ^ 1);
  26. }
  27. if (prepre == 0) {// 一定要改变
  28. // pre这个灯,一定要变,pre前灯的状态,改变! 前前 -> 1
  29. pre ^= 1;
  30. int cur = arr[index] ^ 1;
  31. int next = process1(arr, index + 1, pre, cur);
  32. return next == Integer.MAX_VALUE ? next : next + 1;
  33. } else {// 一定不能改变
  34. return process1(arr, index + 1, pre, arr[index]);
  35. }
  36. }

迭代版本

  1. public static int noLoopMinStep2(int[] arr) {
  2. if (arr == null || arr.length == 0) {
  3. return 0;
  4. }
  5. if (arr.length == 1) {
  6. return arr[0] == 1 ? 0 : 1;
  7. }
  8. if (arr.length == 2) {
  9. return arr[0] != arr[1] ? Integer.MAX_VALUE : (arr[0] ^ 1);
  10. }
  11. int p1 = traceNoLoop(arr, arr[0], arr[1]);
  12. int p2 = traceNoLoop(arr, arr[0] ^ 1, arr[1] ^ 1);
  13. p2 = (p2 == Integer.MAX_VALUE) ? p2 : (p2 + 1);
  14. return Math.min(p1, p2);
  15. }
  16. public static int traceNoLoop(int[] arr, int prepre, int pre) {
  17. int i = 2;
  18. int op = 0;
  19. while (i != arr.length) {
  20. if (prepre == 0) {
  21. op++;
  22. prepre = pre ^ 1;
  23. pre = arr[i++] ^ 1;
  24. } else {
  25. prepre = pre;
  26. pre = arr[i++];
  27. }
  28. }
  29. return (prepre != pre) ? Integer.MAX_VALUE : (op + (pre ^ 1));
  30. }