荷兰国旗算法

逆序对:如果列表中左边的数比右边的大,称为逆序对
或者说右边的数比左边小

如果求相邻的那么直接遍历比较即可

如果不相邻也算,那么可以利用拆分排序(左边无序,右边有序(提高查询效率,二分法查等于他或者比他大一点数为位置))
第一次拆为2个数组左边是从头到倒数第二位,末尾一个
第二次左边头到N-2,右边N-2和n-12个有序的
…第X次左边头到N-X,右边倒数的X个数字(N-X,N有序)

荷兰国旗:
一个数组arr,将大于num的放在右边,小于num的放在左边
实际上就是粗排序,声明2个临时数组,左边和右边,大于的放在右边,小于的放在左边,这种方案时间复杂度0(N),但是额外空间复杂度不好

减少额外空间复杂度,可以考虑数组中直接不符合的交换即可
声明3个int变量l=0,r=len-1,mid=r+(r-l)>>1
遍历数组,获取0-mid中大于num的角标集合(有序,正序)Z
和mid-尾部的小于num的角标集合(有序,正序)Y
对比ZY长度,遍历长度小的,2者交换

处理剩余的,Z头部还处在比num大的X个,那么和mid左边的x个交换,
尾部剩余比num小的和mid右边的换

更优:不借助临时数组存储角标,遍历中直接交换

从头开始遍历:遍历过程中发现当前角标i>num,从尾部遍历数组(范围尾部到i看是否有小num的,如果有没有就做到前面小于=后面大于)

荷兰国旗:
如果要做到小于在前面,等于在中间,大于在后面
头部遍历,
1.碰见大于,找尾部倒序的第一个大于等于的交换,交换,记录尾部游标end,找不到就代表当前完成了排序
2.碰见等于,从smallInedx(第一次默认当前位置+1,后续对比smallIndex和当前开始)开始找到end,第一个小于交换,记录小于开始位置smallInedx(方便下次直接从此处寻找,如果节点碰撞代表后面没有小的了,后面不找了,next)
3,小于直接next

实现如下:
/*
* 小于num的在左边,等于中间,大于放右边
* */

public int[] sLeftAndBRight(int[] a, int num) {
    //边界校验省略

    //完成标志,碰到大于后面找不到小于等于即视为成功
    boolean successFlag = false;

    //尾部查找小于等于的起始位置
    int endSmall = a.length - 1;

    //碰到等于时,找后面第一个小于num的位置
    int smallIndex = 0;

    for (int i = 0; i < a.length; ) {
        int tmp = a[i];

        //大于找从尾部找小于等于的交换,停在原地,处理交换过来的(交换过来的可能是等于)
        if (tmp > num) {
            for (int j = endSmall; j > i; j--) {
                int tmpEnd = a[j];
                if (tmpEnd <= num) {
                    swap(a, i, j);
                    endSmall = j - 1;
                    break;
                }
                //如果之后无小于等于那么直接跳出
                if (j == i + 1) {
                    successFlag = true;
                }
            }
        } else if (tmp == num) {
            //等于,从当前角标向后到尾部endSmall范围内找第一个小于当前的
            smallIndex = smallIndex > i + 1 ? smallIndex : i + 1;
            if (smallIndex <= endSmall) {
                for (int j = smallIndex; endSmall >= j; j++) {
                    int tmpEnd = a[j];
                    if (tmpEnd < num) {
                        swap(a, i, j);
                        smallIndex = j + 1;
                        break;
                    }

                    //如果范围内无,对比下一个
                    if (j == endSmall) {
                        i++;
                    }
                }

                //如果smallIndex>end代表中间已经无小于的了,i++
            } else {
                i++;
            }

            if (endSmall <= i) {
                break;
            }

        } else {
            //小于直接跳过,next
            i++;
        }
        if (successFlag) {
            break;
        }
    }

    for (int i = 0; i < a.length; i++) {
        System.out.print(a[i] + ",");

    }
    return a;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值