快速排序——封闭图形个数

封闭图形个数

题目描述

​ 在蓝桥王国,数字的大小不仅仅取决于它们的数值大小,还取决于它们所形成的“封闭图形”的个数。

​ 封闭图形是指数字中完全封闭的空间,例如数字 1、2、3、5、7 都没有形成封闭图形,而数字 0、4、6、9 分别形成了 1 个封闭图形,数字 8 则形成了 2个封闭图形。值得注意的是,封闭图形的个数是可以累加的。例如,对于数字68,由于 6 形成了 1 个封闭图形,而 8 形成了 2 个,所以 68 形成的封闭图形的个数总共为 3。

​ 在比较两个数的大小时,如果它们的封闭图形个数不同,那么封闭图形个数较多的数更大。例如,数字 41 和数字 18,它们对应的封闭图形的个数分别为 1 和 2,因此数字 41 小于数组 18。如果两个数的封闭图形个数相同,那么数值较大的数更大。例如,数字 14 和数字 41,它们的封闭图形的个数都是 1,但 14 < 41,所以数字 14 小于数字 41。如果两个数字的封闭图形个数和数值都相同,那么这两个数字被认为是相等的。

​ 小蓝对蓝桥王国的数字大小规则十分感兴趣。现在,他将给定你 n 个数a1, a2, . . . , an,请你按照蓝桥王国的数字大小规则,将这 n 数从小到大排序,并输出排序后结果。

输入格式

​ 输入的第一行包含一个整数 n ,表示给定的数字个数。

​ 第二行包含 n 个整数 a1, a2, . . . , an ,相邻整数之间使用一个空格分隔,表示待排序的数字。

输出格式

输出一行包含 n 个整数,相邻整数之间使用一个空格分隔,表示按照蓝桥王国的数字大小规则从小到大排序后的结果。

样例输入

3
18 29 6

样例输出

6 29 18

解题思路

快速排序方法,只需要将比较大小的方法进行更改即可。

代码

import java.util.Scanner;

public class Main {
    //封闭图形个数
    public static final String graphic="1000101021";
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        //封闭图形个数
        String graphic="1000101021";

        String[] nums=new String[n];
        scanner.nextLine();
        for (int i = 0; i < n; i++) {
            nums[i]=scanner.next();
        }
        quickSort(nums, 0, n-1);
        for(int i=0;i<n;i++){
            System.out.print(nums[i]+' ');
        }
    }

    public static void quickSort(String[] nums, int low, int high) {
        if (low < high) {
            // 获取分区点索引
            int pi = partition(nums, low, high);

            // 递归排序左半部分
            quickSort(nums, low, pi - 1);
            // 递归排序右半部分
            quickSort(nums, pi + 1, high);
        }
    }

    private static int partition(String[] nums, int low, int high) {
        // 选择最后一个元素作为基准
        String pivot = nums[high];
        // 指向小于基准区域的最后一个元素
        int i = low - 1;

        // 遍历数组,将小于基准的元素交换到左侧区域
        for (int j = low; j < high; j++) {
            if (compare(pivot,nums[j])) {
                i++;
                // 交换元素
                swap(nums, i, j);
            }
        }

        // 将基准元素放到正确位置
        swap(nums, i + 1, high);
        return i + 1; // 返回基准的最终位置
    }

    public static void swap(String[] nums,int i,int j){
        String temp;
        temp=nums[i];
        nums[i]=nums[j];
        nums[j]=temp;
    }


    //比较两数大小
    public static boolean compare(String a,String b){
       int a_graphic=0,b_graphic=0;
       for(int i=0;i<a.length();i++){
           a_graphic+=graphic.charAt(a.charAt(i)-'0')-'0';
       }

        for(int i=0;i<b.length();i++){
            b_graphic+=graphic.charAt(b.charAt(i)-'0')-'0';
        }
        if(a_graphic==b_graphic){
            int a_num=Integer.parseInt(a),b_num=Integer.parseInt(b);
            return a_num>=b_num;
        }else
            return a_graphic>=b_graphic;
    }
}

快速排序代码模板

//快速排序主方法
public static void quickSort(int[] arr, int low, int high) {
	if (low < high) {
        // 获取分区点索引
        int pi = partition(arr, low, high);

        // 递归排序左半部分
        quickSort(arr, low, pi - 1);
        // 递归排序右半部分
        quickSort(arr, pi + 1, high);
    }
}

//分区函数
private static int partition(int[] arr, int low, int high) {
    // 选择最后一个元素作为基准
    int pivot = arr[high];
    // 指向小于基准区域的最后一个元素
    int i = low - 1;

    // 遍历数组,将小于基准的元素交换到左侧区域
    for (int j = low; j < high; j++) {
        if (arr[j] <= pivot) {
            i++;
            // 交换元素
            swap(arr, i, j);
        }
    }

    // 将基准元素放到正确位置
    swap(arr, i + 1, high);
    return i + 1; // 返回基准的最终位置
}
//交换元素
private static void swap(int[] arr, int i, int j) {
    int temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}

Java交换数组元素

java交换数组元素时可以直接使用的原因,即与C语言的差别。

C语言中的数组传递

  1. 数组退化为指针
    在C语言中,数组作为函数参数时,会退化为指向首元素的指针(如int arr[]等价于int *arr)。函数内部接收到的是数组的内存地址,通过指针可以直接修改原数组的内容。
  2. 无法直接交换数组本身
    若需交换两个数组(如交换int a[10]int b[10]),需通过指针的指针(如int **),因为直接传递数组名只能修改数组元素,无法修改数组变量本身的指向。
  3. 元素交换需指针操作
    交换数组元素必须通过指针或下标访问内存地址,例如:
void swap(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}
// 调用:swap(&arr[i], &arr[j]);

Java中的数组传递

  1. 数组是对象,传递引用副本
    Java中的数组是对象,存储在堆中。方法参数传递的是数组对象的引用(内存地址)的副本。虽然引用本身是副本,但它与原引用指向同一对象,因此可以直接修改数组元素。

  2. 直接通过引用操作元素
    在方法中通过形参(如int[] arr)修改元素(如arr[i] = x),实际是修改堆中的原数组对象,因此无需显式使用指针语法:

void swap(int[] arr, int i, int j) {
    int temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}
  1. 无法修改原引用指向
    如果尝试在方法内让形参指向新数组(如arr = new int[10];),只会修改引用副本,原数组引用不受影响。

关键区别

特性 C语言 Java
参数传递本质 传递数组首元素指针 传递数组对象引用的副本
能否直接修改元素 是(通过指针) 是(通过引用副本访问堆对象)
能否交换数组本身 需指针的指针(int ** 不能(只能交换元素)
语法显式性 需显式使用指针操作 隐藏指针,语法更简洁

posted @ 2025-03-24 23:54  狐狸胡兔  阅读(90)  评论(0)    收藏  举报