数据结构-Java实现-数组

数组逆置

//完美的数组逆置算法
//给定整形数组,实现数组的逆置;要求时间复杂度为O(N),空间复杂度为O(1)。
//如1234567-〉7654321
public class InverseIntArray{
    //最基本的交换函数
    public void swap(int[] array, int a, int b){
        int t = array[a];
        array[a] = array[b];
        array[b] = t;
    }
    //打印
    public void printArray(int[] array){
        for(int i:array){
            System.out.print(i+"");
        }
        System.out.println();
    }
    //逆置方法1,指针从两头向中间移动
    public void inverse01(int[] array){
        if(array==null||array.length<=1){
            return;
        }
        for(int i=0,j=array.length-1; i<j; i++,j--){
            swap(array, i, j);
        }
    }
    //逆置方法2,在方法1的基础上用n-1-i替代j指针
    public void inverse02(int[] array){
        if(array==null||array.length<=1){
            return;
        }
        int n=array.length;
        int half=n/2;
        for(int i=0;i<half;i++){
            swap(array;i;n-1-i);
        }
    }

}
//在方法1和2基础上改进的泛型方法
public class InverseArray<T> {
    public void swap(T[] array, int a, int b){
        T t = array[a];
        array[a] = array[b];
        array[b] = t;
    }
    public void printArray(T[] array){
        for(T i:array){
            System.out.print(i.toString()+"");    //打印时注意调用toString()方法
        }
        System.out.println();
    }
    public void inverse(T[] array){
        if(array==null||array.length<=1){
            return;
        }
        for(int i=0,j=array.length-1; i<j; i++,j--){    //这里依旧可以优化
            swap(array, i, j);
        }
    }
}
//自己创建的类型
public class Person{
    private int id;
    private String name;
    public int getId() {
        return id;
    }
    public void setId() {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Person(int id, String name) {
        super();
        this.id = id;
        this.name = name;
    }
    //重写toString方法
    @Override
    public String toString() {
        return "Person [id="+ id + ",name=" + name + "]";
    }
}

public class TestInverse {
    @Test
    public void testPerson(){
        Person[] array=new Person[6];    //创建Person类型的对象
        for(int i=0;i<6;i++){
            array[i]=new Person(i, "name" + i);
        }
        InverseArray<Person> ia=new InverseArray<Person>();    //创建泛型对象
        ia.printArray(array);
        ia.inverse(array);
        ia.printArray(array);
    }
    @Test
    public void testInteger(){
        Integer[] array=new Integer[7];    //创建封装整型对象进行测试
        Randon ra = new Random();
        for(int i=0;i<7;i++){
            array[i]=ra.nextInt(10);
        }
        InverseArray<Integer> ia=new InverseArray<Integer>();
        ia.printArray(array);
        ia.inverse(array);
        ia.printArray(array);
    }
}

数组旋转

//利用数组逆置算法的数组旋转
//给定一个数组,长度为n,要求把后k个元素移动至前面,前n-k个元素移动至后面。
//时间复杂度O(N)
//空间复杂度O(1)
//reverse(array,0,n-k-1);//反转前一半
//reverse(array,n-k,n-1);//反转后一半
//reverse(array,0,n-1);//反转整个数组
//k=0时不予考虑
//k很有可能大于n,例如n=7,k=24,此时k=k%n=24%7=3
public class RotateArray {
    //基本的指定下标数组元素交换算法
    public void swap(T[] array, int a, int b){
        T t = array[a];
        array[a] = array[b];
        array[b] = t;
    }
    public void printArray(T[] array){
        for(T i:array){
            System.out.print(i.toString()+"");
        }
        System.out.println();
    }
    public void inverse(T[] array, int start, int end){
        if(array==null||array.length<=1){
            return;
        }
        //双指针,对指定下标数组元素进行逆置
        for(int i=start,j=end; i<j; i++,j--){
            swap(array, i, j);
        }
    }
    //第二个参数k指的是旋转点
    public voie rotate(int[] nums, int k){
        if(k==0){
            return;
        }
        int n=nums.length;
        if(k>n){
            k=k%n;
        }
        reverse(nums,0,n-1-k); //旋转前半部分
        reverse(nums,n-k,n-1);  //旋转后半部分
        reverse(nums,0,n-1);  //整体旋转
    }
    @Test
    public void test(){
        int[] nums={1,2,3,4,5,6,7,8,9,10};
        printArray(nums);
        rotate(nums,4);
        printArray(nums);
    }
}

和为s的两个数

public class TwoSum{
    public void printResult(int a, int b){
    System.out.println("["+ a + "," + b + "}");
    }
    //最基本的双循环遍历方法,时间复杂度O(n^2),不推荐
    public void twoSum01(int[] array,int s){
        int n = array.length;
        for(int i=0; i<n-1; i++){
            for(int j=i+1; j<n; j++){
                if(array[i]+array[j]==s){
                    printResult(array[i],array[j]);
                    break;  //之所以break是因为一旦找到,再往后遍历和肯定大于s,无须继续遍历
                }
            }
        }
    }
    @Test
    public void test(){
        in[] array={1,3,4,5,8,9,12};
        int s=13;
        twoSum01(array, s);
    }
    //类似数组逆置的双指针方法
    public void twosum02(in[] array,int s){
        int i=0;
        int j=array.length-1;
        int sum=0;
        while(i<j){
            sum=array[i]+array[j];
            if(sum==s){
                printResult(array[i],array[j]);  //找到s时,i后移,j前移,减小范围
                i++;
                j--;
            }else if(sum<s){
                i++;  //sum小于s时,i后移,刚好可以递增
            }else{ 
                j--;  //sum大于s时,j前移,刚好可以递减
            }
        }
    }

}

//二分查找,根据i指针指向的数和s寻找another数是否存在,需要用Arrays类的binarySearch方法
public void twoSum03(int[] array,int s){
    int n=array.length;
    for(int i=0; i<n-1; i++){
        int another=s-array[i];
        if(Arrays.binarySearch(array,i+1,n-1,another)>=i+1){  //if判别保证寻找区域在i之后
            printResult(array[i], another);
        }
    }
}

和为s的连续正整数序列

//和为s的连续正整数序列
public class SeriesSum {
    public void printResult(int start, int end){
        for(int k=start; k<=end; k++){
            System.out.print(k+" ");
        }
        System.out.println();
    }
    //依旧是双指针遍历,设置half为界
    public void addSum(int s){
        int start=1,end=2;
        int sum=start+end;
        int half=(s+1)/2;
        while(start<half){
            if(sum=s){
                //如果sum=s,打印,并将start和end后移一位,更新临时变量sum,减去start加上end
                printResult(start, end);
                sum=sum-start;
                start++;
                end++;
                sum+=end;
            }else if(sum<s){
                //如果sum<s,end后移,并将值累加至临时变量sum
                end++;
                sum+=end;
            }else{
                //如果sum>s,start后移,临时变量sum减去start
                sum=sum-start;
                start++;
            }
        }
    }
    @Test
    public void test(){
        addSum(21);
        System.out.println();
        addSum(15);
    }
}

删除数组中的重复元素

class RemoveDuplicates{
    //第一种方式
    //ArrayList,时间复杂度和空间复杂度都为O(n),因为重新开辟了一个ArrayList
    public int remove01(int[] nums){
        if(nums==null||nums.length==0){
            return 0;
        }else if(nums.length==1){
            return 1;
        }else{
            int end=nums.length-1;
            ArrayList<Integer> list=new ArrayList<Integer>();
            int i=0;
            while(i<=end){
                if(i==end){
                    list.add(nums[i]);
                    i++;
                }else{
                    //j指针放在i指针后面,假如i和j的值相同,则j指针后移知道两个值不相同
                    int j=i+1;
                    if(nums[i]==nums[j]){
                        while(j<=end&&nums[i]==nums[j]){
                            j++;  //相同元素则j指针后移
                        }
                    }
                    list.add(nums[i]);  //不同的元素则加入到开辟的list中 
                    i=j;  //加入后将j赋值给i,i指针移动到和j相同的位置
                }
            }
            //将list数组的的值覆盖nums数组
            for(i=0;i<list.size();i++){
                nums[i]=list.get(i);
            }           
            return list.size();
        }
    }
    //ArrayCopy    
    public int remove02(int[] nums){
        if(nums==null||nums.length==0){
            return 0;
        }else if(nums.length==1){
            return 1;
        }else{
            int end=nums.length-1;
            //for循环的时间复杂度O(n)*移动数组的时间复杂度O(n),总的时间复杂度O(n^2)
            for(int i=0;i<=end;i++){
                if(i<end){
                    int j=i+1;
                    //j指针从第二个数开始,判断是否重复,重复则j指针后移
                    if(nums[i]==nums[j]){
                        while(j<=end&&nums[i]==nums[j]){
                            j++;
                        }
                    }
                    //不同之处是当遇到不同时,将从j开始的数组覆盖到i+1开始长度为end-j+1的数组,也就是重复的数组
                    System.arraycopy(nums, j, nums, i+1, end-j+1);
                    //数组长度同时也缩小了j-i-1;
                    end-=j-i-1;
                }
            }
            return end+1;
        }
    }
    //自己写的ArrayCopy,但会超时
    public void myArrayCopy(int[] array1, int s1, int[] array2, int s2,int length){
        int[] array=new int[len];
        for(int i=0; i<len; i++){
            array[i]=array1[s1+i];  //将array1数组从s1开始往后的元素赋予array,长度为len
        }
        for(int i=0; i<len; i++){
            array2[s2+i]=array[i];  //将array数组覆盖至array2数组从下标s2开始的地方,长度为len
        }
    }

    public void printNewArray(int[] array,int len){
        for(int i=0;i<len;i++){
            System.out.print(array[i]+" ");
        }
        System.out.println();
    }
    @Test
    public void test01{
        int[] nums={1,2,2,2,3,4,5,6,6,7,7,7,8};
        int len=remove01(nums);
        System.out.println(len);
        printNewArray(nums, len);
    }
    @Test
    public void test02{
        int[] nums={1,2,2,2,3,4,5,6,6,7,7,7,8};
        int len=remove02(nums);
        System.out.println(len);
        printNewArray(nums, len);
    }
    //临时变量,最佳解法 时间复杂度为O(n),空间复杂度为O(1),数组下标和临时变量是数组题两大法宝
    public int remove02(int[] nums){
        if(nums==null||nums.length==0){
            return 0;
        }else if(nums.length==1){
            return 1;
        }else{
            int temp=nums[0];
            int len=1;
            for(int i=1; i<nums.length;i++){
                if(temp==nums[i]){
                    continue;  //相同的元素则i指针后移
                }else{
                    temp=nums[i];  //不同则赋予temp以进行下一次比较
                    nums[len]=nums[i];  //并将不同的值赋予nums[len]以覆盖重复的值
                    len++;  //len下标自增以指向下一个位置,用以存放不同的数
                }
                return len;
            }
        }
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值