算法:输入一个int类型的值N,构造一个长度为N的数组arr并返回 要求:对任意的i < k < j,都满足arr[i] + arr[j] != arr[k] * 2

这是一道算法面试题,百度找到的答案不多,就算能找到也只是给出其实现代码,没把其原理讲清楚,分享一下我对这道题的看法。

一、分析

题目是:
输入一个int类型的值N,构造一个长度为N的数组arr并返回,要求:对任意的i < k < j,都满足arr[i] + arr[j] != arr[k] * 2。
既然要任意的i < k < j,就说明最少要有三个元素,那么就先可以定义一个满足这条件的数组

 int[] data = new int[]{1,3,2};

该数组满足题目的要求,但是题目要求的输入一个N,生成长度为N的数组,也就是说生成的数组长度不是固定好了的,那么我们可以对已经满足条件的数组进行变换,写出一套算法,让其生成的任意长度的数组都满足该要求。

二、算法

如何让一个满足条件的数组变换出更多满足条件的数组呢?

①元素值加减
在数学中,不等式两边加上一个共同的数不等式符号不变

//已知
arr[i] + arr[j] != arr[k] * 2;
//给每个元素加上n,就变成了
arr[i]+n+ arr[j] +n!= (arr[k]+n) * 2;
//稍加变换等于
arr[i]+ arr[j] +2n!= 2arr[k]+n) * 2n;

两边都加了一个2n不等式是依旧成立,同理,减去一个n也照样成立。

②元素值乘正数

还有一点,不等式两边乘以一个正数,不等式符号不变。

 //已知
 arr[i] + arr[j] != arr[k] * 2;
//给每个元素乘n(n>0)就变成了
arr[i]*n+ arr[j] *n!=(arr[k]*n)*2; 
//稍加变换等于
n*(arr[i]+ arr[j])!= arr[k] *2n;

两边同乘n,不等式依旧成立。

③取奇偶值
这个方法挺奇妙的,意思是取出数组元素,然后将元素对应的奇数或者偶数写入新数组。
我们知道,已知一个数n,
第n个偶数为:2×n (我们让2为第一个偶数)
第n个奇数为:2×(n-1)+1
下面开始证明

 //已知
 arr[i] + arr[j] != arr[k] * 2;
//取偶数就变成了
2*arr[i]+ 2*arr[j] !=(arr[k]*2)*2; 
//稍加变换等于
2*(arr[i]+ arr[j])!= arr[k] *2*2;

使用取偶数的方法生成的新数组等于两边同乘2,依旧满足要求。

 //已知
 arr[i] + arr[j] != arr[k] * 2;
//取奇数就变成了
2*(arr[i]-1)+1+ 2*(arr[j]-1)+1 !=((arr[k]-1)*2+1)*2; 
//稍加变换等于
2*(arr[i]+ arr[j])-2!= arr[k] *2*2-2;

相当于给不等式两边先乘2,再共同减2,所以取奇数的方法生成的新数组依旧满足要求。

上述方法生成的元素个数是不变的,那么怎么扩大数组呢?
方法就是:两个变换方法一起使用将生成的两个新数组进行合并,如果长度大于要求的长度就减掉一部分

①加法减法一起使用
在数组:1 3 2 的基础上,新数组a为:2 4 3,新数组b为:0 2 1
两个数组合并:2 4 3 0 2 1
可以看出 4 + 2 = 3×2
不满足要求,该方法pass。
②乘法加法一起用
在数组:1 3 2 的基础上,生成长度为4的数组,新数组a为:2 4 3,新数组b为:2 6 4
两个数组合:2 4 3 2
可以看出 4 + 2 = 3×2
不满足要求,该方法pass。

其他方法除了取奇偶方法合用外生成的数组都无法满足条件,读者可自行验证,这里不再赘述。
为什么取奇偶数的方法能成功呢?
其实想一想,合并之后,i、j、k取值分为三种情况:

  1. i和j取值都在奇数这边,毫无疑问不等式肯定是成立的 ,因为本身没合并前就成立;
  2. i和j取值都在偶数这边,同上这也肯定是成立的;
  3. i取在奇数,j取在偶数,arr[i] + arr[j]必定为奇数,而 2*arr[k]必定为偶数,所以不等式照样成立!

三、代码实现

上述讨论的时候,起始数组为1 3 2,其实该数组也是通过变换得来的,首先获得一个基本数组a[1] = {1},通过奇偶取值变换获得新数组a[2] = {1,2}(长度为偶数时偶数部分和奇数部分都取相同个数的元素),再次通过奇偶取值变换获得新数组a[3] = {1,3,2}(长度为奇数时奇数部分个数大于偶数部分),通过此方法而来的。
因此可以看出,如果要获取长度为N且符合条件的数组,就得利用递归思想,从只有一个元素开始,直到长度为N。
给出示例代码(java):

public class one {
    public static int[] GetData(int size) {
        int o, j;
        if (size == 1) {
            return new int[]{1};
        }
        j = (size + 1) / 2;
        int[] temp = GetData(j);
        o = size - j;
        int[] js = new int[j];//奇数
        int[] os = new int[o];//偶数
        for (int i = 0; i < j; i++) {
            js[i] = 2*(temp[i]-1)+1;
        }
        for (int i = 0;i < o; i++) {
            os[i] = 2*temp[i];
        }
        int[] data = new int[size];
        for (int i = 0, m = 0, n = 0; i < size; i++) {
            if (i < j)
                data[i] = js[m++];
            else
                data[i] = os[n++];
        }
        return data;
    }
    //检验函数
    public static boolean JudgeData(int[] data) {
        for (int i = 0; i < data.length; i++)
            for (int j = i + 1; j < data.length; j++)
                for (int k = j + 1; k < data.length; k++)
                    if (data[i] + data[k] == 2 * data[j]) {
                        System.out.println(data[i] + " " + data[k] + " " + data[j]);
                        return false;
                    }
        return true;
    }
    public static void main(String[] args) {
        int i = 0;
        while(i<=100) {
            int[] data = GetData(i++);
            if (JudgeData(data)) {
                System.out.println("构造成功!");
            } else {
                System.out.println("构造失败!");
            }
        }
    }
}

注:因为main函数为静态函数,静态函数无法调用其他非静态函数,所以其他方法也都设置成了静态方法,并无其他意义。
顺便给出C代码:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int one[] = {1};
int* GetData(int size) {
    int o,j;
    if (size == 1) {
        return one;
    }
    j = (size + 1) / 2;
    int *temp = GetData(j);
    o = size - j;
    int *js = (int *)malloc(j);//奇数
    int *os = (int *)malloc(o);//偶数
	int i,m,n;
    for ( i = 0; i < j; i++) {
        js[i] = 2*(temp[i]-1)+1;
    }
    for (i = 0;i < o; i++) {
        os[i] = 2*temp[i];
    }
    int *data = (int *)malloc(size);
    for (i = 0, m = 0, n = 0; i < size; i++) {
        if (i < j)
            data[i] = js[m++];
        else
            data[i] = os[n++];
    }
    return data;
}
int JudgeData(int* data) {
    for (int i = 0; i < sizeof(data); i++)
        for (int j = i + 1; j < sizeof(data); j++)
            for (int k = j + 1; k < sizeof(data); k++)
                if (data[i] + data[k] == 2 * data[j]) {
                    return 0;
                }
    return 1;
}
int main(void) 
{
	int i = 1;
    while(i<6)
	{
		int *data = GetData(i++);
		if (JudgeData(data) == 1) {
			printf("构造成功!\n");
		} else {
		   printf("构造失败!\n");
		}
	}
    return 0;
}

注:因为c每次都要给数组主动开辟空间,太多了卡死了,所以只试了1-5。
到此结束!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值