原题链接 : http://lintcode.com/zh-cn/problem/interleaving-positive-and-negative-numbers/
Given an array with positive and negative integers. Re-range it to interleaving with positive and negative integers.
You are not necessary to keep the original order or positive integers or negative integers.
Given [-1, -2, -3, 4, 5, 6], after re-range, it will be [-1, 5, -2, 4, -3, 6] or any other legal answer.
Do it in-place and without extra memory.
1. 先用parition把数组分为左边为负数,右边为正数。
2. 如果负数比较多,把多余的负数与尾部的值交换。(这样多余的数会放在数组的末尾)
3. left 指向数组的左边,right指向数组的右边减掉多余的数。
4. 第3步中,根据是正数多,还是负数多,起始位置要变一下。正数多,我们希望开始的是正数:
例如 3 -1 2
负数多,我们希望开始的是负数,如 -1 3 -2
5. 不断交换left, right指针,并一次前进步长2. 直到left, right 相遇。
1 class Solution { 2 /** 3 * @param A: An integer array. 4 * @return an integer array 5 */ 6 // SOLUTION 2: 判断正数多还是负数多。 7 public static int[] rerange(int[] A) { 8 // write your code here 9 10 // Check the input parameter. 11 if (A == null || A.length == 0) { 12 return A; 13 } 14 15 int len = A.length; 16 17 int left = -1; 18 int right = A.length; 19 20 // divide the negative and positive integers. 21 while (true) { 22 while (left < A.length - 1 && A[++left] < 0); 23 24 while (left < right && A[--right] > 0); 25 26 if (left >= right) { 27 break; 28 } 29 30 swap(A, left, right); 31 } 32 33 // LEFT: point to the first positive number. 34 int negNum = left; 35 int posNum = len - left; 36 37 int les = Math.min(negNum, posNum); 38 int dif = Math.abs(negNum - posNum); 39 40 // 如果负数比较多,把多的负数扔到后面去 41 if (negNum > posNum) { 42 int cnt = dif; 43 int l = les; 44 int r = len - 1; 45 while (cnt > 0) { 46 swap(A, l, r); 47 l++; 48 r--; 49 cnt--; 50 } 51 52 // 负数多的时候,负数在前,反之,正数在前 53 left = -1; 54 // 跳过右边不需要交换的值 55 right = A.length - dif; 56 } else { 57 // 正数在前 58 left = -2; 59 // 跳过右边不需要交换的值 60 right = A.length - dif + 1; 61 } 62 63 /* 64 -1 -2 -5 -6 3 4 les = 2; 65 4 -2 -5 -6 3 -1 66 */ 67 // swap the negative and the positive 68 while (true) { 69 left += 2; 70 right -= 2; 71 72 if (left >= les) { 73 break; 74 } 75 swap(A, left, right); 76 } 77 78 return A; 79 } 80 81 public static void swap(int[] A, int n1, int n2) { 82 int tmp = A[n1]; 83 A[n1] = A[n2]; 84 A[n2] = tmp; 85 } 86 }
1. 扫一次确定是正数多还是负数多
2. 把奇数索引的所有的数字进行partition,如果是正数多,把正数放在后面,否则负数放在后面。
3. 令Index 1 = 奇数列,index 2 = 偶数列,扫描一次,遇到不符合正负条件的数字进行交换即可
1 public static void swap(int[] A, int n1, int n2) { 2 int tmp = A[n1]; 3 A[n1] = A[n2]; 4 A[n2] = tmp; 5 } 6 7 /* 8 Solution 2: 9 */ 10 public static int[] rerange(int[] A) { 11 // write your code here 12 13 // Check the input parameter. 14 if (A == null || A.length <= 2) { 15 return A; 16 } 17 18 int len = A.length; 19 20 int cntPositive = 0; 21 22 for (int num: A) { 23 if (num > 0) { 24 cntPositive++; 25 } 26 } 27 28 // If positive numbers are more than negative numbers, 29 // Put the positive numbers at first. 30 int posPointer = 1; 31 int negPointer = 0; 32 33 // means 34 boolean pos = false; 35 36 if (cntPositive > A.length / 2) { 37 // Have more Positive numbers; 38 posPointer = 0; 39 negPointer = 1; 40 41 pos = true; 42 } 43 44 int i = 1; 45 int j = len - 2; 46 47 if (pos) { 48 while (true) { 49 // Put the positive numbers at the end. 50 if (i < len && A[i] < 0) { 51 i += 2; 52 } 53 54 if (j > i && A[j] > 0) { 55 j -= 2; 56 } 57 58 if (i >= j) { 59 break; 60 } 61 62 swap(A, i, j); 63 } 64 } else { 65 while (true) { 66 // Put the negative numbers at the end. 67 if (i < len && A[i] > 0) { 68 i += 2; 69 } 70 71 if (j > i && A[j] < 0) { 72 j -= 2; 73 } 74 75 if (i >= j) { 76 break; 77 } 78 79 swap(A, i, j); 80 } 81 } 82 83 // Reorder the negative and the positive numbers. 84 while (true) { 85 // Should move if it is in the range. 86 while (posPointer < len && A[posPointer] > 0) { 87 posPointer += 2; 88 } 89 90 // Should move if it is in the range. 91 while (negPointer < len && A[negPointer] < 0) { 92 negPointer += 2; 93 } 94 95 if (posPointer >= len || negPointer >= len) { 96 break; 97 } 98 99 swap(A, posPointer, negPointer); 100 } 101 102 return A; 103 }
在SOL2的基础上改进:
1. 在统计正负数个数时,把负数放在最后。
2. 如果发现正数比较多,把数列翻转。
3. 令Index 1 = 奇数列,index 2 = 偶数列,扫描一次,遇到不符合正负条件的数字进行交换即可
1 /* 2 Solution 3: 3 */ 4 public static int[] rerange(int[] A) { 5 // write your code here 6 7 // Check the input parameter. 8 if (A == null || A.length <= 2) { 9 return A; 10 } 11 12 int len = A.length; 13 14 int cntPositive = 0; 15 16 // store the positive numbers index. 17 int i1 = 0; 18 19 for (int i2 = 0; i2 < len; i2++) { 20 if (A[i2] > 0) { 21 cntPositive++; 22 23 // Put all the positive numbers at in the left part. 24 swap(A, i1++, i2); 25 } 26 } 27 28 // If positive numbers are more than negative numbers, 29 // Put the positive numbers at first. 30 int posPointer = 1; 31 int negPointer = 0; 32 33 if (cntPositive > A.length / 2) { 34 // Have more Positive numbers; 35 posPointer = 0; 36 negPointer = 1; 37 38 // Reverse the array. 39 int left = 0; 40 int right = len -1; 41 while (left < right) { 42 int tmp = A[left]; 43 A[left] = A[right]; 44 A[right] = tmp; 45 left++; 46 right--; 47 } 48 } 49 50 // Reorder the negative and the positive numbers. 51 while (true) { 52 // Should move if it is in the range. 53 while (posPointer < len && A[posPointer] > 0) { 54 posPointer += 2; 55 } 56 57 // Should move if it is in the range. 58 while (negPointer < len && A[negPointer] < 0) { 59 negPointer += 2; 60 } 61 62 if (posPointer >= len || negPointer >= len) { 63 break; 64 } 65 66 swap(A, posPointer, negPointer); 67 } 68 69 return A; 70 }
在SOL3的基础上改进:
翻转数列的一步修改为:把右边的负数移动到左边即可。可以优化复杂度。其它与SOL3一致。
感谢Lansheep大神提供思路!
1 /* 2 Solution 4: 3 把reverse的步骤简化了一下 4 */ 5 public static int[] rerange(int[] A) { 6 // write your code here 7 8 // Check the input parameter. 9 if (A == null || A.length <= 2) { 10 return A; 11 } 12 13 int len = A.length; 14 15 int cntPositive = 0; 16 17 // store the positive numbers index. 18 int i1 = 0; 19 20 for (int i2 = 0; i2 < len; i2++) { 21 if (A[i2] > 0) { 22 cntPositive++; 23 24 // Put all the positive numbers at in the left part. 25 swap(A, i1++, i2); 26 } 27 } 28 29 // If positive numbers are more than negative numbers, 30 // Put the positive numbers at first. 31 int posPointer = 1; 32 int negPointer = 0; 33 34 if (cntPositive > A.length / 2) { 35 // Have more Positive numbers; 36 posPointer = 0; 37 negPointer = 1; 38 39 // Reverse the array. 40 int left = 0; 41 int right = len -1; 42 while (right >= cntPositive) { 43 swap(A, left, right); 44 left++; 45 right--; 46 } 47 } 48 49 // Reorder the negative and the positive numbers. 50 while (true) { 51 // Should move if it is in the range. 52 while (posPointer < len && A[posPointer] > 0) { 53 posPointer += 2; 54 } 55 56 // Should move if it is in the range. 57 while (negPointer < len && A[negPointer] < 0) { 58 negPointer += 2; 59 } 60 61 if (posPointer >= len || negPointer >= len) { 62 break; 63 } 64 65 swap(A, posPointer, negPointer); 66 } 67 68 return A; 69 }
https://github.com/yuzhangcmu/LeetCode_algorithm/blob/master/lintcode/array/Rerange.java