【问题标题】:Place positive numbers before negative将正数放在负数之前
【发布时间】:2021-05-14 16:11:06
【问题描述】:

所以我有这段代码,我在互联网上找到了一个包含负数和正数的数组并重新排列数组,因此所有负数都在正数之前。但是每个数字的出现位置必须保持不变。因此,例如,如果我有 -2 5 -9 .....,则在有组织的数组中,-2 仍然必须是 负数first 数,而 -9 必须是second negative 个,5 必须是 positive 个的first 个数。

示例:

Input: {1,7,-5,9,-12,15,-6,-8}
Output:{-5,-12,-6,-8,1,7,9,15}

所以代码工作正常,但我想做的是改变它,使正数出现在负数之前。

示例:

Input: {1,7,-5,9,-12,15,-6,-8}
Output:{1,7,9,15,-5,-12,-6,-8}

这是代码,如果你能帮助我,我知道它不是很复杂,但我无法弄清楚。

// 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);
    }
}

【问题讨论】:

  • 一种快速而肮脏的方法是运行代码,找到分区点并交换两组。
  • 保留当前代码,但增加3个步骤:反转正子数组,反转负子数组,反转整个数组。
  • @Bohemian♦ 有没有办法将代码设计为将正数放在负数之前?我认为您所说的是保持精确的设计,但在此功能完成后交换两个子数组。我希望该函数以正确的方式对数组进行排序,而无需在函数完成后进行额外的更改。我不知道你是否明白我的意思。
  • 我的猜测:将 while 循环条件从 &lt; 0 更改为 &gt;= 0(假设零被认为是正数)
  • 有时,更好的答案就是重新开始。这种排序可以使用Arrays.sort 和一个比较器来实现,该比较器将所有负数视为相等,所有正数视为相等,负数视为小于正数。请注意,您需要 Integer[] 而不是 int[]

标签: java arrays sorting recursion


【解决方案1】:

你可以filter这个数组中的两个子流positivenegative,然后concat他们。这大大简化了您的代码:

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();
}

如果你想交换positivenegative 子流,你可以交换filters的部分:i &lt; 0i &gt;= 0


另见:Rotating an int Array in Java using only one semicolon

【讨论】:

    【解决方案2】:

    通过将Predicate&lt;Integer&gt; 参数添加到方法rearrangePosNegmerge 可以轻松地对现有解决方案进行参数化,并且根据此参数,正值或负值将放置在数组的开头:

    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);
    }
    

    那么就可以调用rearrangePosNeg方法了:

    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);
    

    输出:

    1 7 9 15 -5 -12 -6 -8 
    

    此外,使用新数组和几个索引的更简单的迭代解决方案是可能的:

    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;
    }
    

    测试:

    int[] arr = {1,7,-5,9,-12,15,-6,-8};
    
    System.out.println("iterative: " +  Arrays.toString(rearrange(arr, (x) -> x > 0)));
    

    输出:

    iterative: [1, 7, 9, 15, -5, -12, -6, -8]
    

    更新

    没有Predicate参数,merge函数中的条件需要反转:

    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);
    }
    

    【讨论】:

    • 我喜欢您的解决方案,但我不熟悉您使用的 Predicate 类。没有那个东西你能不能完成这项工作。我只是想让它先积极后消极,我不需要同时拥有这两种可能性。如果可以请编辑该代码,我将不胜感激。我不需要迭代版本,它需要是递归的分治算法。
    • @ChrisCosta,我提供了更新,虽然它有点微不足道
    • 非常感谢,如果您了解 rearrangePosNeg 函数的作用,您能否给我一个简短的解释,因为我很难理解这段代码的作者真正做了什么。我想这是一个分而治之的算法,但我无法理解他是如何解决这个问题的,每次减少lr 的值。如果您能帮助我理解,我将不胜感激。感谢您已经提供的帮助。
    猜你喜欢
    • 2013-02-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-31
    • 1970-01-01
    • 2015-09-03
    • 1970-01-01
    • 2021-12-13
    相关资源
    最近更新 更多