题目描述(困难难度)

238. Product of Array Except Self - 图1

返回一个数组,第 i 个位置存储原数组除了第 i 个数以外的所有数的乘积。

解法一

最直接的想法就是先把所有的数乘起来,然后对于需要返回的数组的第 i 个位置,只需要将所有数的累乘结果除以第 i 个数即可。

如果所有数的累乘结果记为 mul,返回的数组用 res 存储,原数组用 nums 存储,那么

res[i] = mul / nums[i]

除法的话需要考虑除零的问题,如果 nums 中有一个 0,那么 res 除了 0 的那个位置的结果是其余数累乘,其余位置的结果就都是 0 了。

如果 nums0的个数超过一个,那么 res 所有结果就都是 0 了。

  1. public int[] productExceptSelf(int[] nums) {
  2. int mul = 1;
  3. int zeroNums = 0;
  4. int zeroFirst = -1;
  5. for (int i = 0; i < nums.length; i++) {
  6. if (nums[i] == 0) {
  7. zeroNums++;
  8. if (zeroNums == 1) {
  9. zeroFirst = i;
  10. }
  11. continue;
  12. }
  13. mul *= nums[i];
  14. }
  15. int[] res = new int[nums.length];
  16. if (zeroNums > 1) {
  17. return res;
  18. }else if(zeroNums == 1){
  19. res[zeroFirst] = mul;
  20. return res;
  21. }
  22. for (int i = 0; i < nums.length; i++) {
  23. res[i] = mul / nums[i];
  24. }
  25. return res;
  26. }

当然了题目中说不能用除法,恰巧在 29 题 我们用加减法实现过除法,这里的话就可以直接调用了。

  1. public int[] productExceptSelf(int[] nums) {
  2. int mul = 1;
  3. int zeroNums = 0;
  4. int zeroFirst = -1;
  5. for (int i = 0; i < nums.length; i++) {
  6. if (nums[i] == 0) {
  7. zeroNums++;
  8. if (zeroNums == 1) {
  9. zeroFirst = i;
  10. }
  11. continue;
  12. }
  13. mul *= nums[i];
  14. }
  15. int[] res = new int[nums.length];
  16. if (zeroNums > 1) {
  17. return res;
  18. } else if (zeroNums == 1) {
  19. res[zeroFirst] = mul;
  20. return res;
  21. }
  22. for (int i = 0; i < nums.length; i++) {
  23. res[i] = divide(mul, nums[i]);
  24. }
  25. return res;
  26. }
  27. //下边是 29 题实现的除法
  28. public int divide(int dividend, int divisor) {
  29. long ans = divide((long) dividend, (long) (divisor));
  30. long m = 2147483648L;
  31. if (ans == m) {
  32. return Integer.MAX_VALUE;
  33. } else {
  34. return (int) ans;
  35. }
  36. }
  37. public long divide(long dividend, long divisor) {
  38. long ans = 1;
  39. long sign = 1;
  40. if (dividend < 0) {
  41. sign = opposite(sign);
  42. dividend = opposite(dividend);
  43. }
  44. if (divisor < 0) {
  45. sign = opposite(sign);
  46. divisor = opposite(divisor);
  47. }
  48. long origin_dividend = dividend;
  49. long origin_divisor = divisor;
  50. if (dividend < divisor) {
  51. return 0;
  52. }
  53. dividend -= divisor;
  54. while (divisor <= dividend) {
  55. ans = ans + ans;
  56. divisor += divisor;
  57. dividend -= divisor;
  58. }
  59. long a = ans + divide(origin_dividend - divisor, origin_divisor);
  60. return sign > 0 ? a : opposite(a);
  61. }
  62. public long opposite(long x) {
  63. return ~x + 1;
  64. }

解法二

也没有想到其他的解法,分享一个 官方 给的解法。

只要看到这张图,应该就明白算法了。

238. Product of Array Except Self - 图2

白色部分表示当前准备求解的位置,其结果就是粉色部分数字的累乘再乘上黄色部分数字的累乘。换句话说,其实就是左右两部分的累乘结果再相乘

所以我们只需要把所有粉色结果和黄色结果提前保存起来,然后可以直接去计算结果了。

假设数组个数是 n

我们用 left[i]存储下标是 0 ~ i - 1 的数累乘的结果。

right[i] 存储下标是 i + 1 ~ n - 1 的数累乘的结果。

那么 res[i] = left[i] * right[i]

至于边界情况,我们把 left[0]right[n - 1]初始化为 1 即可。

  1. public int[] productExceptSelf(int[] nums) {
  2. int n = nums.length;
  3. int left[] = new int[n];
  4. left[0] = 1;
  5. for (int i = 1; i < n; i++) {
  6. left[i] = left[i - 1] * nums[i - 1];
  7. }
  8. int right[] = new int[n];
  9. right[n - 1] = 1;
  10. for (int i = n - 2; i >= 0; i--) {
  11. right[i] = right[i + 1] * nums[i + 1];
  12. }
  13. int res[] = new int[n];
  14. for (int i = 0; i < n; i++) {
  15. res[i] = left[i] * right[i];
  16. }
  17. return res;
  18. }

当然,我们可以省去 leftright 数组,先用 res 存储 left 数组的结果,然后边更新 right ,边和 res 相乘。

  1. public int[] productExceptSelf(int[] nums) {
  2. int n = nums.length;
  3. int res[] = new int[n];
  4. res[0] = 1;
  5. for (int i = 1; i < n; i++) {
  6. res[i] = res[i - 1] * nums[i - 1];
  7. }
  8. int right = 1;
  9. for (int i = n - 2; i >= 0; i--) {
  10. right = right * nums[i + 1];
  11. res[i] = res[i] * right;
  12. }
  13. return res;
  14. }

解法二应该是出题人的意思,关键就是认识到那个图,有种分类的意思,把其余的数分成了左半部分和右半部分。解法一的话有种作弊的感觉,哈哈。

windliang wechat

添加好友一起进步~

如果觉得有帮助的话,可以点击 这里 给一个 star 哦 ^^

如果想系统的学习数据结构和算法,强烈推荐一个我之前学过的课程,可以点击 这里 查看详情