问题
So I have this code which I found on the internet which takes an array of negative and positive numbers and rearranges the array so all negative numbers are before the positive ones. But the position of appearance of each number has to remain the same. So for example if i have -2 5 -9 .....
, in the organized array -2
still has to be the first number of the negative ones and -9
has to be the second of the negative ones, also 5
has to be the first number of the positive ones.
Example:
Input: {1,7,-5,9,-12,15,-6,-8}
Output:{-5,-12,-6,-8,1,7,9,15}
So the code is working correctly but what I want to do is to change it so positive numbers appear before the negative ones.
Example:
Input: {1,7,-5,9,-12,15,-6,-8}
Output:{1,7,9,15,-5,-12,-6,-8}
Here's the code please if you can help me, I know that it's not very complicated but I can't figure it out.
// Java program to Rearrange positive and negative
// numbers in a array
public class Rearrangement {
/* Function to print an array */
static void printArray(int[] A, int size) {
for (int i = 0; i < size; i++)
System.out.print(A[i] + " ");
System.out.println("");
}
/* Function to reverse an array. An array can be
reversed in O(n) time and O(1) space. */
static void reverse(int[] arr, int l, int r) {
if (l < r) {
arr = swap(arr, l, r);
reverse(arr, ++l, --r);
}
}
// Merges two subarrays of arr[].
// First subarray is arr[l..m]
// Second subarray is arr[m+1..r]
static void merge(int[] arr, int l, int m, int r) {
int i = l; // Initial index of 1st subarray
int j = m + 1; // Initial index of IInd
while (i <= m && arr[i] < 0)
i++;
// arr[i..m] is positive
while (j <= r && arr[j] < 0)
j++;
// arr[j..r] is positive
// reverse positive part of
// left sub-array (arr[i..m])
reverse(arr, i, m);
// reverse negative part of
// right sub-array (arr[m+1..j-1])
reverse(arr, m + 1, j - 1);
// reverse arr[i..j-1]
reverse(arr, i, j - 1);
}
// Function to Rearrange positive and negative
// numbers in a array
static void RearrangePosNeg(int[] arr, int l, int r) {
if (l < r) {
// Same as (l+r)/2, but avoids overflow for
// large l and h
int m = (l + r) / 2;
// Sort first and second halves
RearrangePosNeg(arr, l, m);
RearrangePosNeg(arr, m + 1, r);
merge(arr, l, m, r);
}
}
static int[] swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
return arr;
}
public static void main(String[] args) {
int[] arr = {1, 7, -5, 9, -12, 15, -6, -8};
int arr_size = arr.length;
RearrangePosNeg(arr, 0, arr_size - 1);
printArray(arr, arr_size);
}
}
回答1:
Existing solution may be easily parameterized by adding a Predicate<Integer>
argument to methods rearrangePosNeg
and merge
and depending on this argument the positive or negative values will be placed at the beginning of the array:
static void rearrangePosNeg(int[] arr, int l, int r, Predicate<Integer> p) {
if (l < r) {
// Same as (l+r)/2, but avoids overflow for large l and r
int m = l - (l - r)/2;
// Sort first and second halves
rearrangePosNeg(arr, l, m, p);
rearrangePosNeg(arr, m + 1, r, p);
merge(arr, l, m, r, p);
}
}
static void merge(int[] arr, int l, int m, int r, Predicate<Integer> p) {
int i = l; // Initial index of 1st subarray
int j = m + 1; // Initial index of IInd
while (i <= m && p.test(arr[i])) i++;
while (j <= r && p.test(arr[j])) j++;
reverse(arr, i, m);
reverse(arr, m + 1, j - 1);
reverse(arr, i, j - 1);
}
Then the rearrangePosNeg
method can be invoked:
int[] arr = {1,7,-5,9,-12,15,-6,-8};
int arr_size = arr.length;
rearrangePosNeg(arr, 0, arr_size - 1, (x) -> x > 0); // put positives first
printArray(arr, arr_size);
Output:
1 7 9 15 -5 -12 -6 -8
Also, a simpler iterative solution using a new array and a couple of indexes is possible:
static int[] rearrange(int[] arr, Predicate<Integer> p) {
int n = arr.length;
int[] rearranged = new int[n--];
for (int i = 0, iFirst = 0, iLast = n; i <= n; i++) {
if (p.test(arr[i])) {
rearranged[iFirst++] = arr[i]; // copying by condition to the head
}
if (!p.test(arr[n - i])) {
rearranged[iLast--] = arr[n - i]; // copying opposite to the tail
}
}
return rearranged;
}
Test:
int[] arr = {1,7,-5,9,-12,15,-6,-8};
System.out.println("iterative: " + Arrays.toString(rearrange(arr, (x) -> x > 0)));
Output:
iterative: [1, 7, 9, 15, -5, -12, -6, -8]
Update
Without the Predicate
parameter, the condition in merge
function needs to be inverted:
static void rearrangePosNeg(int[] arr, int l, int r) {
if (l < r) {
// Same as (l+r)/2, but avoids overflow for large l and r
int m = l - (l - r)/2;
// Sort first and second halves
rearrangePosNeg(arr, l, m);
rearrangePosNeg(arr, m + 1, r);
merge(arr, l, m, r);
}
}
static void merge(int[] arr, int l, int m, int r) {
int i = l; // Initial index of 1st subarray
int j = m + 1; // Initial index of IInd
while (i <= m && arr[i] > 0) i++;
while (j <= r && arr[j] > 0) j++;
reverse(arr, i, m);
reverse(arr, m + 1, j - 1);
reverse(arr, i, j - 1);
}
回答2:
You can filter two substreams from this array: positive and negative, and then concat them. This greatly simplifies your code:
public static void main(String[] args) {
int[] arr = {1, 7, -5, 9, -12, 15, -6, -8};
System.out.println(Arrays.toString(rearrangePosNeg(arr)));
// [-5, -12, -6, -8, 1, 7, 9, 15]
}
public static int[] rearrangePosNeg(int[] arr) {
return IntStream.concat(
Arrays.stream(arr) // negative
.filter(i -> i < 0),
Arrays.stream(arr) // positive
.filter(i -> i >= 0))
.toArray();
}
If you want to swap the positive and negative substreams, you can swap the parts of the filters: i < 0
and i >= 0
.
See also: Rotating an int Array in Java using only one semicolon
来源:https://stackoverflow.com/questions/66145933/place-positive-numbers-before-negative