算法-秒杀数组元素位置调整类问题

这类题目有点特别,不要求我们对数组元素进行像正常排序那样从大到小或者从小到大,而是要求我们使用O(N)的方法将符合条件的元素排在前面或者后面。其实这是排序的一种变形,不需要我们消灭逆序数。

解决思路有两类:
1、利用快排思想,将符合条件数据放在前面或后面,一遍遍历即可完成
2、指针的思想
2、利用冒泡排序思想,我们将符合条件的数据冒在前面,而且我们不需要消灭逆序数,因此每个元素访问2次,所以时间复杂度仍然是O(N)

1、给定一个数组,将奇数(正数…etc)排在左边,偶数排在右边

以奇数为例,使用快排思想,快排中我们选择的枢纽元其实是作为一个条件出现的,而在这里,只不过这个“枢纽元”换成了奇数偶数而已。

    /**
     * 利用快排思想,复杂度O(n)
     * @param nums
     */
    public static void reOrder(int[] nums){
        int left=0,right=nums.length-1;
        while(left<right){
            while (left<right&&(nums[left]&1)==1){left++;}//找到第一个偶数
            while(left<right&&(nums[right]&1)==0){right--;}//找到第一个奇数
            if(left<right){
                swap(nums,left,right);//交换数据
            }
        }
    }

我们还可以有另一种操作: 指针法

使用一个指针指向当前第一个不符合条件的位置,然后遍历数组,每次遇到符合条件的,我们就可以将其交换,这样就可以实现题目要求。而且这个方法写起来非常简洁

public static void reOrder(int[] nums){
	int ptr=0;
	for(int i=0;i<nums.length;i++){
		if((nums[i]&1)==1){//判断奇数偶数
			swap(nums,ptr++,i);
		}
	}
}

2、给定一个数组,将奇数(正数…etc)排在左边,偶数排在右边(保证相对位置不变)

这类题目和上面相比,稍微复杂了点,这里要求我们维持相对顺序不变。冒泡法给我们带来了希望。已经冒过的位置不在冒泡,说明每个元素被访问了两次,所以时间复杂度为O(N)

我们也用一个指针指向第一个不符合条件的位置,然后遍历数组,冒泡冒到那个位置

public static void reOrder(int[] nums){
	int ptr=0;
	for(int i=0;i<nums.length;i++){
		if((nums[i]&1)==1){//判断奇偶数
			int curr=i;
			while(curr>ptr){//冒到第一个不符合条件的那个位置
				swap(nums,curr,--curr);//前后交换
			}
			ptr++;
		}
	}
}

2中的代码可以直接放在1中使用

	//交换元素
    public static void swap(int[] nums,int i,int j){
        int temp=nums[i];
        nums[i]=nums[j];
        nums[j]=temp;
    }

3、将数组中0移动到数组尾部

题目很简单,直接套壳就好了。。。

    public void moveZeroes(int[] nums) {
        int ptr=nums.length-1;
        for(int i=nums.length-1;i>=0;i--){
           if(nums[i]==0){
               int curr=i;
               while(curr<ptr){
                int temp=nums[curr];
                nums[curr]=nums[curr+1];
                nums[curr+1]=temp;
                curr++;
               }
               ptr--;
           }
        }
    }

不过,我们其实可以针对本题进行优化。因为我们知道特定的数据为0,那么我们就可以统计非零个数,然后将后面置零。

    public void moveZeroes(int[] nums) {
        int noZeroIndex=0;
        for(int i=0;i<nums.length;i++){
            if(nums[i]!=0){
                nums[noZeroIndex++]=nums[i];
            }
        }
        for(int i=noZeroIndex;i<nums.length;i++){
            nums[i]=0;
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值