常见算法题(包括华为机试题)

2023-11-01

一、维护O(1)时间查找最大元素的栈

问题描述:一个栈stack,具有push和pop操作,其时间复杂度皆为O(1)。设计算法max操作,

求栈中的最大值,该操作的时间复杂度也要求为O(1)。

可以修改栈的存储方式,push,pop的操作,但是要保证O(1)的时间复杂度,空间时间复杂

度无要求。

可以创建一个类,类里有两个栈,一个栈S维持正常的push、pop操作,另一个Sm保存当前的最大值

假设元素以5,4,1,2,3,10,9,8,6,7,15顺序入栈,则两个栈中存储的元素如下图所示:

S    5    4    1    2    3    10    9    8    6    7    15

Sm 5    10  15

struct max_stack{
    stack<int> s1;
    stack<int> sm;
};
max_stack s;
void my_push(int k) {
    if(!s.s1.empty()){
        if(k>s.sm.top()) s.sm.push(k);
        s.s1.push(k);
    } else {
        s.s1.push(k);   s.sm.push(k);
    }
}
void my_pop() {
    if(!s.s1.empty()) {
        if(s.s1.top()==s.sm.top())  s.sm.pop();
        s.s1.pop();
    }
}
int my_max() {
    if(!s.s1.empty()) {
        return s.sm.top();
    }
}

二、约瑟夫环问题

瑟夫环问题的原来描述为,设有编号为1,2,……,n的n(n>0)个人围成一个圈,从第1个人

开始报数,报到m时停止报数,报m的人出圈,再从他的下一个人起重新报数,报到m时停止

报数,报m的出圈,……,如此下去,直到所有人全部出圈为止。当任意给定n和m后,设计

算法求n个人出圈的次序。换一种表述如下

问题描述:n个人(编号0~(n-1)),从0开始报数,报到(m-1)的退出,剩下的人继续从0开始

报数。求胜利者的编号。

具体数学上给出通项公式:

f(0)=0      

f(n)=(f(n-1)+m)%n    ,    (n>1)

int joseph(int n,int m) {
    int *f=new int[n+1];
    f[0]=f[1]=0;
    for(int i=2;i<n+1;i++) 
        f[i]=(f[i-1]+m)%i;
    int result=f[n];
    delete []f;
    return result;
}

如果求解原表述的解,只需要将result加1即可。

三、寻找明星

问题描述:有个聚会有N人参加,其中N-1个是群众。1个是明星。其中所有群众都认识明星,

明星不认识任何群众,群众之前是否认识不知道。

假设有个机器人能问问题A是否认识B?时间复杂度为O(1),那么设计一个算法用最小的复

杂度找出明星。

从问题的描述中可以知道,对于任意两个人A、B,如果A认识B那么A一定不是明星;如果A不

认识B,那么B一定不是明星。将所有人存储在数组中,每次比较询问A[0]是否认识A[1],将一

定不是明星的人放在数组的最后,并且在以后可以不用管了。代码描述如下

int famous(int A[],int n) {
    int j=n;
    while(j>1) {
        if(A[0] knows A[1]) 
            swap(A[0],A[1]);
        swap(A[1],A[--j]);
    }
    return A[0];
}

由于询问和交换的时间复杂度是O(1),while循环进行了n-1次,所以时间复杂度是O(n).

四、最小交流次数

问题描述:有n个战士其中n>4他们手中都有不同的情报,假设每个人通过交流能过得双方所有

的情报。设计一个算法使得用最少的交流次数使得所有的战士都获得全部的情报,给出算法并

给出最小交流次数?

可以建立递推式:

                       f(4)=4

                       f(n)=f(n-1)+2  ,  n>4

假设在战士人数是n-1时需要f(n-1)次交流,则增加一个人时,如下步骤进行:

1、第n个战士和前面任意一个战士交流一次

2、前n-1个战士互相交流,使得前面n-1个战士都有所有战士获得的情报

3、第n个战士和前面任意一个战士交流一次。

这样n个战士都有所有情报了。

五、数星星

问题描述:A和B晚上无聊就开始数星星。每次只能数K个(20<=k<=30)A和B轮流数。最后

谁把星星数完谁就获胜,那么当星星数量为多少时候A必胜?

这是一个博弈的问题,我们可以从胜利条件出发,A必胜,那么最后一次是A数,并且剩下星星

的个数 20<=k<=30 ,那么如何保证呢?最后50颗由B先数,B数m颗,然后A数剩下的50-m

颗。好了,那么第一次A数的话必须保证,第一次A数完之后,剩下的个数是50的倍数。所以

案就明了了,星星的数量应满足   

50k+20 <= N <=50K+30    ,    k是整数

六、求连续子数组的最大和

这是一个动态规划问题递推式为

M(i)=max{M(i-1)+a(i),a(i)},i>0

int max_sub_sum(int *A,int n) {
    int thissum=0,maxsum=0;
    for(int i=0;i<n;i++) {
        thissum+=A[i];
        if(thissum>maxsum)    maxsum=thissum;
        if(thisum<0)          thisum=0;
    }
    return maxsum;
}

七、二分查找

用二分法查找已排序的大小为n的数组A是否存在value,如果存在返回下标,否则返回-1。

int b_search(int *A,int n,int value) {
    int low=0,high=n-1;
    while(low<=high) {
        int mid=(low+high)/2;
        if(A[mid]==value)        return mid;
        else if(A[mid]>value)    high=mid-1;
        else                     low=mid+1;
    }
    return -1;
}
 
 

1.从考试成绩中划出及格线

(1)及格线是10的倍数

(2)保证至少有60%的学生及格

(3)如果有所有的学生都高于60分,则及格线为60分。

算法分析:

关键信息点为“保证至少有60%的学生及格”,可将分数线的概念转换为人数,即只需统计每个档次的人数,若60以上档次的人数就是全体人员则分数线为60,否则去寻找(由高分到低分)最先达到60%人数的档次。

java实现如下:

  1. public class Exam{
  2. public int findPassLine(int[] scores){
  3. int num=scores.length;
  4. int[] record=new int[num+1];//记录每一个档次的人数
  5. for(int i=0;i<num;i++){
  6. switch(scores[i]/10){
  7. case 10:record[10]++;break;
  8. case 9:record[9]++;break;
  9. case 8:record[8]++;break;
  10. case 7:record[7]++;break;
  11. case 6:record[6]++;break;
  12. case 5:record[5]++;break;
  13. case 4:record[4]++;break;
  14. case 3:record[3]++;break;
  15. case 2:record[2]++;break;
  16. case 1:record[1]++;break;
  17. case 0:record[0]++;break;
  18. }
  19. }
  20. int sumh=0;//记录60分以上所有人数
  21. int suml=0;//记录60分以下所有人数
  22. for(int j=record.length-1;j>=0;j--){
  23. if(j>=6)
  24. sumh+=record[j];
  25. }
  26. suml=10-sumh;
  27. if(sumh==10){//所有人都在60分以上
  28. System.out.println("所有人的分数均高于60,分数线为:");
  29. return 60;
  30. }
  31. else{
  32. //有高分档次向下遍历
  33. for(int k=record.length-1;k>0;k--){//10~0遍历
  34. if(record[k]>=6){
  35. return 10*k;
  36. }
  37. else
  38. record[k-1]+=record[k];//向下累加
  39. }
  40. }
  41. return 0;
  42. }
  43. public static void main(String[] args){
  44. int a[]={99,89,79,69,0,0,4,5,80,50};
  45. System.out.println(new Exam().findPassLine(a));
  46. int b[]={100,100,100,100,100,80,0,0,0,0};
  47. System.out.println(new Exam().findPassLine(b));
  48. int c[]={100,100,100,100,100,100,0,0,0,0};
  49. System.out.println(new Exam().findPassLine(c));
  50. int d[]={100,100,100,100,100,100,60,80,70,90};
  51. System.out.println(new Exam().findPassLine(d));
  52. }
  53. }
public class Exam{
	public int findPassLine(int[] scores){
		int num=scores.length;
		int[] record=new int[num+1];//记录每一个档次的人数
		for(int i=0;i<num;i++){
		  switch(scores[i]/10){
		  	case 10:record[10]++;break;
		  	case 9:record[9]++;break;
		  	case 8:record[8]++;break;
		  	case 7:record[7]++;break;
		  	case 6:record[6]++;break;
		  	case 5:record[5]++;break;
		  	case 4:record[4]++;break;
		  	case 3:record[3]++;break;
		  	case 2:record[2]++;break;
		  	case 1:record[1]++;break;
		  	case 0:record[0]++;break;
		  }
	  }
	  int sumh=0;//记录60分以上所有人数
	  int suml=0;//记录60分以下所有人数
	  for(int j=record.length-1;j>=0;j--){
	  	if(j>=6)
	  	 sumh+=record[j];
	  }
	  suml=10-sumh;
  	if(sumh==10){//所有人都在60分以上
	  		System.out.println("所有人的分数均高于60,分数线为:");
	  		return 60;
	  }
	  else{
	  	//有高分档次向下遍历
		  for(int k=record.length-1;k>0;k--){//10~0遍历
		   	if(record[k]>=6){
		   			return 10*k;	  
		   	}
		   	else
		   	 record[k-1]+=record[k];//向下累加
		  }
	  }
	  return 0;
	}
	
	public static void main(String[] args){
	  int a[]={99,89,79,69,0,0,4,5,80,50};
	  System.out.println(new Exam().findPassLine(a));
	  int b[]={100,100,100,100,100,80,0,0,0,0};
	  System.out.println(new Exam().findPassLine(b));
	  int c[]={100,100,100,100,100,100,0,0,0,0};
	  System.out.println(new Exam().findPassLine(c));
	  int d[]={100,100,100,100,100,100,60,80,70,90};
	  System.out.println(new Exam().findPassLine(d));
	}
}

输出:

50
80
100
所有人的分数均高于60,分数线为:
60

2.亮着电灯的盏数

一条长廊里依次装有n(1 ≤ n ≤ 65535)盏电灯,从头到尾编号1、2、3、…n-1、n。每盏电灯由一个拉线开关控制。开始,电灯全部关着。
有n个学生从长廊穿过。第一个学生把号码凡是1的倍数的电灯的开关拉一下;接着第二个学生把号码凡是2的倍数的电灯的开关拉一下;接着第三个学生把号码凡是3的倍数的电灯的开关拉一下;如此继续下去,最后第n个学生把号码凡是n的倍数的电灯的开关拉一下。n个学生按此规定走完后,长廊里电灯有几盏亮着。
注:电灯数和学生数一致。

算法分析:无任何算法可言,只需要按照题目描述实现一边,不知道有啥捷径

java实现如下:

  1. //import java.lang.StringBuilder;
  2. public class Light{
  3. public int lightNum(int[] lights){
  4. //刚开始默认全部打开,1开,0闭
  5. int i=1,n=lights.length-1,num=0;
  6. while(i<=n){
  7. for(int j=1;j<=n;j++){//遍历1--n栈灯(0号元素忽略)
  8. if(j%i==0){
  9. if(lights[j]==1){
  10. //开着的等被关闭
  11. lights[j]=0;
  12. num--;
  13. }
  14. else if(lights[j]==0) {
  15. //关闭的灯被打开
  16. lights[j]=1;
  17. num++;
  18. }
  19. }
  20. }
  21. i++;//第i个人
  22. }
  23. return num;
  24. }
  25. //打印亮着的编号
  26. public void printLightsNum(int[] lights){
  27. StringBuilder sb=new StringBuilder();
  28. sb.append("它们分别是:");
  29. for(int i=1;i<=lights.length-1;i++){
  30. if(lights[i]==1){//开着
  31. sb.append(" ");
  32. sb.append(i);
  33. }
  34. }
  35. System.out.println(sb.toString());
  36. }
  37. public static void main(String[] args){
  38. for(int i=10;i<=100;i+=10){
  39. System.out.println("初始时"+i+"栈灯灭着!");
  40. int[] lights=new int[i+1];
  41. Light obj=new Light();
  42. System.out.println("触动后还剩下"+obj.lightNum(lights)+"栈灯开着!");
  43. obj.printLightsNum(lights);
  44. System.out.println("--------------------------------------------------");
  45. }
  46. }
  47. }
//import java.lang.StringBuilder;
public class Light{
	
	public int lightNum(int[] lights){
		//刚开始默认全部打开,1开,0闭
		int i=1,n=lights.length-1,num=0;
		while(i<=n){
			for(int j=1;j<=n;j++){//遍历1--n栈灯(0号元素忽略)
				if(j%i==0){
					if(lights[j]==1){
						//开着的等被关闭
						lights[j]=0;
						num--;
					}
					else if(lights[j]==0) {
						//关闭的灯被打开
					 	lights[j]=1;
						num++;
					}
			  }
			}	
			i++;//第i个人
		}
		return num;
	}
	//打印亮着的编号
	public void printLightsNum(int[] lights){
		StringBuilder sb=new StringBuilder();
		sb.append("它们分别是:");
		for(int i=1;i<=lights.length-1;i++){
			if(lights[i]==1){//开着
				sb.append(" ");
				sb.append(i);
			}
		}
		System.out.println(sb.toString());
	}
	
	public static void main(String[] args){
		for(int i=10;i<=100;i+=10){
			System.out.println("初始时"+i+"栈灯灭着!");
			int[] lights=new int[i+1];
			Light obj=new Light();
			System.out.println("触动后还剩下"+obj.lightNum(lights)+"栈灯开着!");
			obj.printLightsNum(lights);
			System.out.println("--------------------------------------------------");
	  }
	}

}


输出:

初始时10栈灯灭着!
触动后还剩下3栈灯开着!
它们分别是: 1 4 9
--------------------------------------------------
初始时20栈灯灭着!
触动后还剩下4栈灯开着!
它们分别是: 1 4 9 16
--------------------------------------------------
初始时30栈灯灭着!
触动后还剩下5栈灯开着!
它们分别是: 1 4 9 16 25
--------------------------------------------------
初始时40栈灯灭着!
触动后还剩下6栈灯开着!
它们分别是: 1 4 9 16 25 36
--------------------------------------------------
初始时50栈灯灭着!
触动后还剩下7栈灯开着!
它们分别是: 1 4 9 16 25 36 49
--------------------------------------------------
初始时60栈灯灭着!
触动后还剩下7栈灯开着!
它们分别是: 1 4 9 16 25 36 49
--------------------------------------------------
初始时70栈灯灭着!
触动后还剩下8栈灯开着!
它们分别是: 1 4 9 16 25 36 49 64
--------------------------------------------------
初始时80栈灯灭着!
触动后还剩下8栈灯开着!
它们分别是: 1 4 9 16 25 36 49 64
--------------------------------------------------
初始时90栈灯灭着!
触动后还剩下9栈灯开着!
它们分别是: 1 4 9 16 25 36 49 64 81
--------------------------------------------------
初始时100栈灯灭着!
触动后还剩下10栈灯开着!
它们分别是: 1 4 9 16 25 36 49 64 81 100
--------------------------------------------------


从输出中反推原理:最后亮着灯的编号都是可以开方的数,这时为什么呢?

题中告知所有灯刚开始是关着的,也就说最后想开着,必须触动开关奇数次,即"该灯所对应的编号数,其公约数有奇数个"。那么问题就转化为"什么样的数有奇数个公约数",由于已经知道答案了(完全平方数),所有只好用反证法。

证: 若对任意实数C具有奇数个公约数,且C不是完全平方数

则有C的任意一对公约数m1!=m2,设C有n对公约数,

则C的公约数总数=n*2+2(可以被自身和1整除)=2*(n+1)为偶数

此结论与已知"C具有奇数个公约数"矛盾,故C是完全平方数。

有了上面的结论,即可以直接去找1--n内的完全平方数即可,复杂度就降为O(n)了,我想这就是华为将此题做为中级难度题目的捷径思路了吧。

3.验证括号是否匹配

输入一串字符串,其中有普通的字符与括号组成(包括‘(’、‘)’、‘[’,']'),要求验证括号是否匹配,如果匹配则输出0、否则输出1.
Smple input:dfa(sdf)df[dfds(dfd)] Smple outPut:0

算法分析:利用栈来实现,所有左括号入栈,遇到右括号就进行出栈,看是否匹配。

java实现:

  1. import java.util.Scanner;
  2. import java.util.Stack;
  3. public class Match{
  4. public static void main(String[] args){
  5. Boolean isMatch=true;
  6. Stack<Character> stack=new Stack<Character>();
  7. Scanner s=new Scanner(System.in);
  8. while(true){
  9. char ch=s.nextLine().charAt(0);
  10. if(ch=='q')
  11. break;
  12. else{
  13. switch(ch){
  14. case '{':;
  15. case '[':;
  16. case '(':
  17. stack.push(ch);break;
  18. case '}':
  19. if(stack.empty())
  20. isMatch=false;
  21. else if(stack.pop()!='{')
  22. isMatch=false;
  23. break;
  24. case ']':
  25. if(stack.empty())
  26. isMatch=false;
  27. else if(stack.pop()!='[')
  28. isMatch=false;
  29. break;
  30. case ')':
  31. if(stack.empty())
  32. isMatch=false;
  33. else if(stack.pop()!=')')
  34. isMatch=false;
  35. break;
  36. }
  37. }
  38. }
  39. if(isMatch)
  40. System.out.println("匹配!");
  41. else
  42. System.out.println("不匹配");
  43. }
  44. }
import java.util.Scanner;
import java.util.Stack;
public class Match{
	public static void main(String[] args){
		Boolean isMatch=true;
		Stack<Character> stack=new Stack<Character>();
		Scanner s=new Scanner(System.in);
		while(true){
			char ch=s.nextLine().charAt(0);
			if(ch=='q')
			  break;
			else{
						switch(ch){
							case '{':;
							case '[':;
							case '(':
								stack.push(ch);break;
							case '}':
								if(stack.empty())
									isMatch=false;
								else if(stack.pop()!='{')
									isMatch=false;
									break;
							case ']':
									if(stack.empty())
									isMatch=false;
								else if(stack.pop()!='[')
									isMatch=false;
									break;
							case ')':
								if(stack.empty())
									isMatch=false;
								else if(stack.pop()!=')')
									isMatch=false;
									break;
						}
				}
		}
		if(isMatch)
			System.out.println("匹配!");
		else
			System.out.println("不匹配");
	}
}


C/C++:

  1. void main()
  2. 13.{//子函数声明
  3. 14. void InitStack(SqStack &S);//初始化空栈
  4. 15. int StackEmpty(SqStack S);//判空
  5. 16. void push(SqStack &S,int e);//进栈
  6. 17. void pop(SqStack &S,int &e);//出栈
  7. 18. //主函数开始
  8. 19. SqStack s;//初始化空栈
  9. 20. InitStack(s);
  10. 21. char ch[100],*p;int e;
  11. 22. p=ch;
  12. 23. printf("输一个含义有()[]{}的括号表达式:\n");
  13. 24. gets(ch);
  14. 25. while(*p)
  15. 26. {
  16. 27. switch (*p)
  17. 28. {
  18. 29. case '{':
  19. 30. case '[':
  20. 31. case '(': push(s,*p++);break;//只要是左括号就入栈
  21. 32. case '}':
  22. 33. case ']':
  23. 34. case ')':pop(s,e);
  24. 35. if ((e=='{' && *p=='}') ||(e=='[' && *p==']') || (e=='(' && *p==')'))
  25. 36. p++;
  26. 37. else
  27. 38. {printf("括号不匹配!");exit(OVERFLOW);}
  28. 39. break;
  29. 40. default :p++;//其他字符就后移
  30. 41. }
  31. 42. }
  32. 43. if (StackEmpty(s))
  33. 44. printf("括号匹配成功");
  34. 45. else
  35. 46. printf("缺少右括号!");
  36. 47. printf("\n");
  37. 48.}
void main()  
13.{//子函数声明   
14.    void InitStack(SqStack &S);//初始化空栈   
15.    int StackEmpty(SqStack S);//判空   
16.    void push(SqStack &S,int e);//进栈   
17.    void pop(SqStack &S,int &e);//出栈   
18.    //主函数开始   
19.    SqStack s;//初始化空栈   
20.    InitStack(s);  
21.    char ch[100],*p;int e;  
22.    p=ch;  
23.    printf("输一个含义有()[]{}的括号表达式:\n");  
24.    gets(ch);  
25.    while(*p)  
26.    {   
27.        switch (*p)  
28.        {  
29.        case '{':  
30.        case '[':  
31.        case '(': push(s,*p++);break;//只要是左括号就入栈   
32.        case '}':  
33.        case ']':  
34.        case ')':pop(s,e);  
35.                 if ((e=='{' && *p=='}') ||(e=='[' && *p==']') || (e=='(' && *p==')'))  
36.                 p++;  
37.                 else  
38.                 {printf("括号不匹配!");exit(OVERFLOW);}  
39.                 break;  
40.        default :p++;//其他字符就后移   
41.        }  
42.    }  
43.    if (StackEmpty(s))  
44.      printf("括号匹配成功");  
45.    else  
46.      printf("缺少右括号!");  
47.    printf("\n");  
48.}  


4.回文数

判断回文数,是返回1
算法分析:既然是对称的,那么从个位开始,逆序反向生成一个数,若该数与原数相同,则是回文数。

  1. Scanner s=new Scanner(System.in);
  2. int num=s.nextInt();
  3. int max=num,min=0;
  4. while(max>0){
  5. min=min*10+max%10;//反向生成
  6. max=max/10;//去除最后一位
  7. }
  8. if(min==max)
  9. System.out.println("Yes");
  10. else
  11. System.out.println("No");
 Scanner s=new Scanner(System.in);
		  int num=s.nextInt();
		  int max=num,min=0;
		  while(max>0){
		  	min=min*10+max%10;//反向生成
		  	max=max/10;//去除最后一位
		  }
		  if(min==max)
		  	System.out.println("Yes");
		  else
		    System.out.println("No");


附:回文数还有一个性质,即数字位数与存在的回文数有如下关系,

1位回文数: 9个

2位回文数: 9个

3位回文数: 90个

4位回文数: 90个

5位回文数: 900个

6位回文数: 900个

即每增加两位,则存在的回文数为原来的10倍。

5.将整数倒序输出,剔除重复数据

输入一个整数,如12336544,或1750,然后从最后一位开始倒过来输出,最后如果是0,则不输出,输出的数字是不带重复数字的,所以上面的输出是456321和571。如果是负数,比如输入-175,输出-571。
算法分析:将每一位存储,存储时剔除重复元素,而后输出。(注意符号)

  1. public static void main(String[] args){
  2. Scanner s=new Scanner(System.in);
  3. int num=s.nextInt();
  4. int[] store=new int[]{99,99,99,99,99,99,99,99,99,99,99,99,99};//初始值不要赋个位数,避免和取余后的数等值
  5. int len=0,tmp=num,last;
  6. while(true){
  7. if(tmp==0)
  8. break;
  9. else{
  10. int lastNum= tmp%10;//取余求最后一位
  11. tmp=tmp/10;
  12. int flag=1;//待插入数组中是否含有该数
  13. for(int k=0;k<=len;k++){
  14. if(store[k]==lastNum){
  15. flag=0;//重复则不插入
  16. break;
  17. }
  18. }
  19. if(flag!=0){
  20. store[len]=lastNum;//需要插入
  21. len++;
  22. }
  23. }
  24. }
  25. //len指向待插入位置
  26. if(num<0)
  27. System.out.print("-");
  28. for(int j=0;j<len;j++){
  29. if(store[j]!=0)
  30. System.out.print(Math.abs(store[j]));
  31. }
  32. }
public static void main(String[] args){	
	 Scanner s=new Scanner(System.in);
		  int num=s.nextInt();
		  int[] store=new int[]{99,99,99,99,99,99,99,99,99,99,99,99,99};//初始值不要赋个位数,避免和取余后的数等值
		  int len=0,tmp=num,last;
		  while(true){
		  	if(tmp==0)
		  		break;
		  	else{
					  	int lastNum= tmp%10;//取余求最后一位
					  	tmp=tmp/10;
					  	int flag=1;//待插入数组中是否含有该数
					  	for(int k=0;k<=len;k++){
					  		if(store[k]==lastNum){
					  			flag=0;//重复则不插入
					  			break;
					  		}
					  	}
					  	if(flag!=0){
					  		store[len]=lastNum;//需要插入
					  		len++;
					  	}
		 	 }
		  }
		  //len指向待插入位置
		  if(num<0)
		  		System.out.print("-");
		  for(int j=0;j<len;j++){
		  	if(store[j]!=0)
		  	System.out.print(Math.abs(store[j]));
		  }
	}


6.大数相减


输入两行字符串正整数,第一行是被减数,第二行是减数,输出第一行减去第二行的结果。

备注:1、两个整数都是正整数,被减数大于减数

示例:

输入:1000000000000001

1

输出:1000000000000000

注意大数用char a[] 存储,用%s接收,一位一位的运算。注意a[0]里的正负号

算法描述:一位一位减,最高位无需借位。不仅可以大减小,也可以小减大(大减小取负即可)。

java实现:

  1. public int[] subtraction(int[] a,int[] b){
  2. int[] c=new int[a.length];
  3. //a[0]...a[n]代表高位到低位
  4. for(int i=c.length-1;i>=0;i--){
  5. //最高位不借位
  6. if(i!=0){
  7. if(a[i]<b[i]){
  8. a[i-1]-=1;//向高位借位
  9. a[i]+=10;
  10. }
  11. }
  12. c[i]=a[i]-b[i];//存储对应位的差值
  13. }
  14. return c;
  15. }
public int[] subtraction(int[] a,int[] b){
		int[] c=new int[a.length];
		//a[0]...a[n]代表高位到低位
		for(int i=c.length-1;i>=0;i--){
			//最高位不借位
			if(i!=0){
					if(a[i]<b[i]){
						a[i-1]-=1;//向高位借位
						a[i]+=10;
					}	
			}
			c[i]=a[i]-b[i];//存储对应位的差值
		}
		return c;
	}


输出:

2 7 8 7 1 0 0 2 9 4 0 7 0 8 3 3 8 7 0 6
- 2 5 1 3 7 3 8 8 8 3 1 7 5 2 3 7 3 6 1 2
----------------------------------------------------
0 2 7 3 3 6 1 4 1 0 8 9 5 5 9 6 5 0 9 4


0 8 4 9 2 7 2 5 7 8 4 8 1 3 1 0 6 1 7 9
- 2 0 2 1 6 0 4 9 2 8 8 0 6 3 3 0 2 0 5 8
----------------------------------------------------
-1 1 7 2 3 3 2 3 5 0 3 2 5 0 1 9 5 8 7 9


6 6 5 5 5 1 1 1 5 6 5 5 1 6 2 1 9 7 2 9
- 0 2 8 5 9 7 5 8 9 8 2 8 0 1 8 5 7 3 3 4
----------------------------------------------------
6 3 6 9 5 3 5 2 5 8 2 7 1 4 3 6 2 3 9 5


3 4 7 5 7 1 1 1 9 1 9 2 2 0 0 4 5 2 9 8
- 5 9 5 6 1 5 8 9 8 9 7 1 9 7 1 2 5 0 3 5
----------------------------------------------------
-2 4 8 0 4 4 7 7 9 7 7 9 7 7 0 7 9 7 3 7


5 1 9 0 4 6 1 6 1 6 5 3 1 9 9 3 8 5 9 5
- 4 0 2 2 8 3 3 4 8 0 9 0 3 5 5 8 3 1 5 0
----------------------------------------------------
1 1 6 7 6 2 8 1 3 5 6 2 8 4 3 5 5 4 4 5


完整代码:

  1. import java.util.Random;
  2. public class Sub{
  3. //判别大小
  4. public Boolean compare(int[] a,int[] b){
  5. Boolean bool=true;//大于
  6. for(int i=0;i<a.length;i++){
  7. //从高位开始遍历
  8. if(a[i]<b[i]){
  9. bool=false;
  10. break;
  11. }
  12. else if(a[i]>b[i]){
  13. bool=true;
  14. break;
  15. }
  16. }
  17. return bool;
  18. }
  19. public int[] subtraction(int[] a,int[] b){
  20. int[] c=new int[a.length];
  21. //a[0]...a[n]代表高位到低位
  22. for(int i=c.length-1;i>=0;i--){
  23. //最高位不借位
  24. if(i!=0){
  25. if(a[i]<b[i]){
  26. a[i-1]-=1;//向高位借位
  27. a[i]+=10;
  28. }
  29. }
  30. c[i]=a[i]-b[i];//存储对应位的差值
  31. }
  32. return c;
  33. }
  34. //输出
  35. public void print(int[] bt){
  36. for(int b : bt){
  37. System.out.print(b+" ");
  38. }
  39. }
  40. public static void main(String[] args){
  41. Random rand=new Random();
  42. for(int i=0;i<5;i++){
  43. Sub sub=new Sub();
  44. int[] a=new int[20];
  45. int[] b=new int[20];
  46. for (int n=0; n<a.length; n++) {
  47. a[n]=rand.nextInt(10);//随机0--9
  48. b[n]=rand.nextInt(10);
  49. }
  50. System.out.print(" ");
  51. sub.print(a);
  52. System.out.println("");
  53. System.out.print("- ");
  54. sub.print(b);
  55. System.out.println("");
  56. System.out.println("------------------------------------------------");
  57. if(sub.compare(a,b)){//保证被减数大于减数
  58. System.out.print(" ");
  59. sub.print(sub.subtraction(a,b));
  60. System.out.println("");
  61. }
  62. else{
  63. System.out.print(" -");
  64. sub.print(sub.subtraction(b,a));
  65. System.out.println("");
  66. }
  67. System.out.println("");
  68. System.out.println("");
  69. }
  70. }
  71. }
import java.util.Random;
public class Sub{
	
	
	
	//判别大小
	public Boolean compare(int[] a,int[] b){
		Boolean bool=true;//大于
		for(int i=0;i<a.length;i++){
			//从高位开始遍历
			if(a[i]<b[i]){
				bool=false;
				break;
			}
			else if(a[i]>b[i]){
				bool=true;
				break;
			}
		}
		return bool;
	}
	
	
	
	public int[] subtraction(int[] a,int[] b){
		int[] c=new int[a.length];
		//a[0]...a[n]代表高位到低位
		for(int i=c.length-1;i>=0;i--){
			//最高位不借位
			if(i!=0){
					if(a[i]<b[i]){
						a[i-1]-=1;//向高位借位
						a[i]+=10;
					}	
			}
			c[i]=a[i]-b[i];//存储对应位的差值
		}
		return c;
	}
	//输出
	public void print(int[] bt){
		for(int b : bt){
			System.out.print(b+" ");
	  }
	  
	 
	}
	
	public static void main(String[] args){
		
		Random rand=new Random();
		for(int i=0;i<5;i++){
			Sub sub=new Sub();
			int[] a=new int[20];
			int[] b=new int[20];
			for (int n=0; n<a.length; n++) {
			 	a[n]=rand.nextInt(10);//随机0--9
			 	b[n]=rand.nextInt(10);
			} 
			System.out.print("    ");
			sub.print(a);
			System.out.println("");
			System.out.print("-   ");
			sub.print(b);
			System.out.println("");
			System.out.println("------------------------------------------------");
			if(sub.compare(a,b)){//保证被减数大于减数
				System.out.print("    ");
				sub.print(sub.subtraction(a,b));
				System.out.println("");
			}
			else{
				System.out.print("   -");
				sub.print(sub.subtraction(b,a));
				System.out.println("");
			}
				 System.out.println("");
				 System.out.println("");
		}
				
		  		
		 
	}
}


7.上海华为的一道关于指针方面的编程题

题目:

int A[nSize],其中隐藏着若干0,其余非0整数,写一个函数int Func(int* A, int nSize),使A把0移至后面,非0整数移至 数组前面并保持有序,返回值为原数据中第一个元素为0的下标。(尽可能不使用辅助空间且考虑效率及异常问题,注释规范且给出设计思路)

思路:
选择一个排序算法对其进行排序,在排序过程中记录0元素的个数count,即nSize-count为首个0元素的下标;需要注意的是,若排序时需由大到小的排序(题中只说保持有序),不然0元素出现在前半部分又要移动元素。

C实现如下:

  1. #include <stdio.h>
  2. using namespace std;
  3. int Func(int *A,int nSize){
  4. if(A!=0&&nSize>0){
  5. int count=0;//记录0元素的个数
  6. //折半插入排序
  7. int low,high,mid;
  8. if(*A==0)
  9. count++;
  10. for(int i=1;i<nSize;i++){
  11. low=0;
  12. high=i-1;
  13. mid=(low+high)/2;
  14. while(low<=high){
  15. if(*(A+i)>*(A+mid))//key>mid
  16. high=mid-1;//注意此处故意倒序排列
  17. else
  18. low=mid+1;
  19. mid=(low+high)/2;
  20. }
  21. //high+1为待插入位置
  22. int key=*(A+i);
  23. //后移元素腾出位置
  24. for(int j=i;j>high+1;j--){
  25. *(A+j)=*(A+j-1);
  26. }
  27. *(A+high+1)=key;//插入
  28. if(key==0)
  29. count++;
  30. }
  31. return nSize-count;
  32. }
  33. else
  34. return -1;
  35. }
  36. void main(){
  37. int a[]={0,3,0,4,9,1,0,44,2,0,12};
  38. int index=Func(a,11);
  39. printf("首个0在 %d 处\n",index);
  40. for(int i=0;i<11;i++){
  41. printf("%d ",a[i]);
  42. }
  43. }
#include <stdio.h>
using namespace std;
int Func(int *A,int nSize){
	if(A!=0&&nSize>0){
		int count=0;//记录0元素的个数
		//折半插入排序
		int low,high,mid;
		if(*A==0)
			count++;
		for(int i=1;i<nSize;i++){
			low=0;
			high=i-1;
			mid=(low+high)/2;
			while(low<=high){
				if(*(A+i)>*(A+mid))//key>mid
					high=mid-1;//注意此处故意倒序排列
				else
					low=mid+1;
				mid=(low+high)/2;
			}
			//high+1为待插入位置
			int key=*(A+i);
			//后移元素腾出位置
			for(int j=i;j>high+1;j--){
				*(A+j)=*(A+j-1);
			}
			*(A+high+1)=key;//插入

			if(key==0)
				count++;
		}
		return nSize-count;
	}
	else
		return -1;
}

void main(){
	int a[]={0,3,0,4,9,1,0,44,2,0,12};
	int index=Func(a,11);
	printf("首个0在 %d 处\n",index);
	for(int i=0;i<11;i++){
		printf("%d ",a[i]);
	}
}

输出:

首个0在 7 处
44 12 9 4 3 2 1 0 0 0 0 请按任意键继续. . .

8.素数问题

题目:
求2~2000的所有素数.有足够的内存,要求尽量快
思路:
查表法,即为2~2000的序列建立对应的表,表大小与序列大小一致(序列需要由小到大排序),选择最小的素数并将其倍数剔除(在表中记录),在剩余的序列中,继续选择最小的素数并剔除其倍数,直到剔除到第N个。这样的好处在于每次遍历时可以参考上次table中的标记,可以避免许多重复操作。
例如在判断4是否为素数时,由于在剔除2的倍数时在表中已经标记为NONPRIME(不是素数),那就不比调用判断素数的方法,省去许多操作。

C实现,为了输出方便,选择10以内的素数

  1. #include <stdio.h>
  2. #include <math.h>
  3. #define TRUE 1
  4. #define FALSE 0
  5. #define NULL -1 //未遍历标记
  6. #define NONPRIME 0//不是素数标记
  7. #define PRIME 1 //是素数标记
  8. #define LEN 10+1 //为了让数组下标一致
  9. using namespace std;
  10. int isPrime(int num){
  11. if(num==2)
  12. return TRUE;
  13. for(int i=2;i<=sqrt((double)num);i++){
  14. if(num%i==0)
  15. return FALSE;
  16. }
  17. return TRUE;
  18. }
  19. //将num的倍数剔除(num为最小质数)
  20. void deleNonPrime(int table[], int num){
  21. table[num]=PRIME;
  22. for(int i=2*num;i<LEN;i+=num){
  23. if(table[i]==NULL){//有可能已经被赋值了
  24. table[i]=NONPRIME;
  25. }
  26. }
  27. }
  28. void print(int arr[],int size){
  29. for(int i=2;i<size;i++){
  30. printf("%d ",arr[i]);
  31. }
  32. printf("\n");
  33. }
  34. void main(){
  35. int primes[LEN]={NULL};
  36. int table[LEN]={NULL};//建立对应的表
  37. for(int i=2;i<LEN;i++){
  38. primes[i]=i;
  39. table[i]=NULL;
  40. }
  41. for(int j=2;j<LEN;j++){
  42. if(j==2){
  43. deleNonPrime(table,2);
  44. }
  45. else{//参考上次表中的标记
  46. if(table[j]==NULL){//有可能为素数(剔除时有可能已经判断过了,避免重复判断)
  47. if(isPrime(primes[j])){
  48. deleNonPrime(table,primes[j]);
  49. }
  50. }
  51. }
  52. printf("序列:");
  53. print(primes,LEN);
  54. printf(" 表:");
  55. print(table,LEN);
  56. printf("\n\n");
  57. }
  58. for(int i=2;i<LEN;i++){
  59. if(table[i]==PRIME)
  60. printf("%d ",i);
  61. }
  62. }
#include <stdio.h>
#include <math.h>
#define TRUE 1
#define FALSE 0
#define NULL -1   //未遍历标记
#define NONPRIME 0//不是素数标记
#define PRIME 1   //是素数标记
#define LEN 10+1  //为了让数组下标一致
using namespace std;

int isPrime(int num){
	if(num==2)
		return TRUE;
	for(int i=2;i<=sqrt((double)num);i++){
		if(num%i==0)
			return FALSE;
	}
	return TRUE;
}
//将num的倍数剔除(num为最小质数)
void deleNonPrime(int table[], int num){
	table[num]=PRIME;
	for(int i=2*num;i<LEN;i+=num){
		
		if(table[i]==NULL){//有可能已经被赋值了
		   table[i]=NONPRIME;
		}
	}
}

void print(int arr[],int size){
	for(int i=2;i<size;i++){
		printf("%d ",arr[i]);
	}
	printf("\n");

}

void main(){
	int primes[LEN]={NULL};
	int table[LEN]={NULL};//建立对应的表
	for(int i=2;i<LEN;i++){
		primes[i]=i;
		table[i]=NULL;
	}
	for(int j=2;j<LEN;j++){
		if(j==2){
			deleNonPrime(table,2);
		}
		else{//参考上次表中的标记
			if(table[j]==NULL){//有可能为素数(剔除时有可能已经判断过了,避免重复判断)
				if(isPrime(primes[j])){
					deleNonPrime(table,primes[j]);
				}
			}
		}
		printf("序列:");
		print(primes,LEN);
		printf("  表:");
		print(table,LEN);
		printf("\n\n");

	}
	for(int i=2;i<LEN;i++){
		if(table[i]==PRIME)
		  printf("%d ",i);
	}

}


输出:

序列:2 3 4 5 6 7 8 9 10
表:1 -1 0 -1 0 -1 0 -1 0


序列:2 3 4 5 6 7 8 9 10
表:1 1 0 -1 0 -1 0 0 0


序列:2 3 4 5 6 7 8 9 10
表:1 1 0 -1 0 -1 0 0 0


序列:2 3 4 5 6 7 8 9 10
表:1 1 0 1 0 -1 0 0 0


序列:2 3 4 5 6 7 8 9 10
表:1 1 0 1 0 -1 0 0 0


序列:2 3 4 5 6 7 8 9 10
表:1 1 0 1 0 1 0 0 0


序列:2 3 4 5 6 7 8 9 10
表:1 1 0 1 0 1 0 0 0


序列:2 3 4 5 6 7 8 9 10
表:1 1 0 1 0 1 0 0 0


序列:2 3 4 5 6 7 8 9 10
表:1 1 0 1 0 1 0 0 0


2 3 5 7 请按任意键继续. . .

注意isPrime函数判断素数时只用判断至sqrt处(素数定理)。

9.操作系统任务调度问题

题目:

操作系统任务分为系统任务和用户任务两种。其中,系统任务的优先级 < 50,用户任务的优先级 >= 50且 <= 255。优 先级大于255的为非法任务,应予以剔除。现有一任务队列task[],长度为n,task中的元素值表示任务的优先级,数值越小,优先级越高。函数scheduler 实现如下功能,将task[] 中的任务按照系统任务、用户任务依次存放到 system_task[] 数组和 user_task[] 数组中(数组中元素的值是任务在task[] 数 组中的下标),并且优先级高的任务排在前面,数组元素为-1表示结束。
例如:
task[] = {0, 30, 155, 1, 80, 300, 170, 40, 99}
system_task[] = {0, 3, 1, 7, -1}
user_task[] = {4, 8, 2, 6, -1}
函数接口 void scheduler(int task[], int n, int system_task[], int user_task[])

思路:

先以50做为关键字对原有序列进行一次快排,返回50的待插入位置location即为系统任务的个数,然后以location做为分界线,左右两边分别进行快排,最后依次将左半部放在system_task[]中,右半部分放在user_task[](需剔除大于255的)

C/C++实现如下:

  1. #include <stdio.h>
  2. using namespace std;
  3. // 利用一趟快速排序找分界线的位置i,即[low,i)为系统任务,[i,high]为用户任务
  4. int findLine(int task[],int lowSpace,int highSpace,int key){
  5. int low=lowSpace,high=highSpace;
  6. while(low<high){
  7. while(low<high&&task[high]>key){
  8. high--;
  9. }
  10. if(low<high){
  11. int tmp=task[high];
  12. task[high]=task[low];
  13. task[low]=tmp;
  14. }
  15. while(low<high&&task[low]<key){
  16. low++;
  17. }
  18. if(low<high){
  19. int tmp=task[low];
  20. task[low]=task[high];
  21. task[high]=tmp;
  22. }
  23. }
  24. return low;
  25. }
  26. void quickSort(int subTask[],int lowSpace,int highSpace){
  27. if(lowSpace<highSpace){//限制递归
  28. int low=lowSpace,high=highSpace;
  29. int insertIndex;//待插入位置
  30. int key=subTask[lowSpace];//关键字
  31. while(low<high){
  32. while(low<high&&subTask[high]>=key){
  33. high--;
  34. }
  35. if(low<high){
  36. int tmp=subTask[high];
  37. subTask[high]=subTask[low];
  38. subTask[low]=tmp;
  39. }
  40. while(low<high&&subTask[low]<=key){
  41. low++;
  42. }
  43. if(low<high){
  44. int tmp=subTask[low];
  45. subTask[low]=subTask[high];
  46. subTask[high]=tmp;
  47. }
  48. }
  49. insertIndex=low;
  50. subTask[insertIndex]=key;
  51. if(insertIndex==lowSpace)
  52. quickSort(subTask,insertIndex+1,highSpace);//只用排高区
  53. else if(insertIndex==highSpace)
  54. quickSort(subTask,lowSpace,insertIndex-1);//只用排低区
  55. else {
  56. quickSort(subTask,lowSpace,insertIndex-1);
  57. quickSort(subTask,insertIndex+1,highSpace);
  58. }
  59. }
  60. }
  61. void scheduler(int task[], int n, int system_task[], int user_task[]){
  62. int index=findLine(task,0,n-1,50);//以50为关键字划分
  63. //分别排序
  64. quickSort(task,0,index);
  65. quickSort(task,index+1,n-1);
  66. int len=0;//记录用户任务的长度,因为需要剔除大于255的数,所以长度不一定为n-index
  67. for(int i=0;i<n;i++){
  68. //系统任务[0,index)
  69. if(i<=index){
  70. system_task[i]=i;
  71. }
  72. //用户任务[index,n)
  73. else if(i>index){
  74. //剔除无效任务
  75. if(task[i]>=50&&task[i]<=255){
  76. user_task[i-index-1]=i;
  77. len++;
  78. }
  79. }
  80. }
  81. system_task[index+1]=-1;//结束
  82. user_task[len]=-1;
  83. }
  84. void printArr(int task[],int n){
  85. for(int i=0;i<n;i++){
  86. printf("%d ",task[i]);
  87. }
  88. printf("\n");
  89. }
  90. //测试
  91. void main(){
  92. int task[]={0, 30, 155, 1, 80, 300, 170, 40, 99};
  93. int system_task[9]={-1};
  94. int user_task[9]={-1};
  95. scheduler(task,9,system_task,user_task);
  96. printf("排序完成后总任务为:\n");
  97. printArr(task,9);
  98. printf("系统任务为:\n");
  99. printArr(system_task,9);
  100. printf("用户任务为:\n");
  101. printArr(user_task,9);
  102. }
#include <stdio.h>
using namespace std;
// 利用一趟快速排序找分界线的位置i,即[low,i)为系统任务,[i,high]为用户任务
int findLine(int task[],int lowSpace,int highSpace,int key){
	int low=lowSpace,high=highSpace;
	while(low<high){
	
		while(low<high&&task[high]>key){
			high--;
		}
		if(low<high){
			int tmp=task[high];
			task[high]=task[low];
			task[low]=tmp;
		}
		while(low<high&&task[low]<key){
			low++;
		}
		if(low<high){
			int tmp=task[low];
			task[low]=task[high];
			task[high]=tmp;
		}
		
	}
	return low;
   
}

void quickSort(int subTask[],int lowSpace,int highSpace){
	
	if(lowSpace<highSpace){//限制递归
		int low=lowSpace,high=highSpace;
		int insertIndex;//待插入位置
		int key=subTask[lowSpace];//关键字
		while(low<high){
	
			while(low<high&&subTask[high]>=key){
				high--;
			}
			if(low<high){
				int tmp=subTask[high];
				subTask[high]=subTask[low];
				subTask[low]=tmp;
			}
			while(low<high&&subTask[low]<=key){
				low++;
			}
			if(low<high){
				int tmp=subTask[low];
				subTask[low]=subTask[high];
				subTask[high]=tmp;
			}
		
		}
		insertIndex=low;
		subTask[insertIndex]=key;
		if(insertIndex==lowSpace)
			quickSort(subTask,insertIndex+1,highSpace);//只用排高区
		else if(insertIndex==highSpace)
			quickSort(subTask,lowSpace,insertIndex-1);//只用排低区
		else {
			quickSort(subTask,lowSpace,insertIndex-1);
			quickSort(subTask,insertIndex+1,highSpace);
		}
	}
}

void scheduler(int task[], int n, int system_task[], int user_task[]){
	int index=findLine(task,0,n-1,50);//以50为关键字划分
	//分别排序
	quickSort(task,0,index);
	quickSort(task,index+1,n-1);
	int len=0;//记录用户任务的长度,因为需要剔除大于255的数,所以长度不一定为n-index
	for(int i=0;i<n;i++){
		//系统任务[0,index)
		if(i<=index){
			system_task[i]=i;
		}
		//用户任务[index,n)
		else if(i>index){
			//剔除无效任务
			 if(task[i]>=50&&task[i]<=255){
				user_task[i-index-1]=i;
				len++;
		     }
			

		}
		
		
	}
	system_task[index+1]=-1;//结束
	user_task[len]=-1;


}

void printArr(int task[],int n){
	for(int i=0;i<n;i++){
	  printf("%d ",task[i]);
	}
	printf("\n");
}
//测试
void main(){
	int task[]={0, 30, 155, 1, 80, 300, 170, 40, 99};
	int system_task[9]={-1};
	int user_task[9]={-1};
	scheduler(task,9,system_task,user_task);
	printf("排序完成后总任务为:\n");
	printArr(task,9);
	printf("系统任务为:\n");
	printArr(system_task,9);
	printf("用户任务为:\n");
	printArr(user_task,9);
}


输出:

排序完成后总任务为:
0 1 30 40 80 99 155 170 300
系统任务为:
0 1 2 3 -1 0 0 0 0
用户任务为:
4 5 6 7 -1 0 0 0 0
请按任意键继续. . .

突然发现自己把题意弄错了,我虽然实现了任务分离和任务,但是题目输出的是原始索引坐标,并不是排序后的。为了实现寻找原始索引,引入一个索引表,只要任务元素被移动,则table的索引随之移动,最后只要查表即可。

C#实现如下:

[csharp] view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. namespace 控制台编程练习
  6. {
  7. class 任务分配
  8. {
  9. //寻找关键字的分界线
  10. int findLine(int[] task,int lowSpace,int highSpace,int key,int[] table){
  11. int low=lowSpace,high=highSpace;
  12. while(low<high){
  13. while(low<high&&task[high]>key){
  14. high--;
  15. }
  16. if(low<high){
  17. swap(high, low, task);
  18. swap(high, low, table);
  19. }
  20. while(low<high&&task[low]<key){
  21. low++;
  22. }
  23. if(low<high){
  24. swap( low,high ,task);
  25. swap(low, high, table);
  26. }
  27. }
  28. return low;
  29. }
  30. //交换
  31. void swap(int a,int b,int[] task){
  32. int tmp= task[a];
  33. task[a]=task[b];
  34. task[b]=tmp;
  35. }
  36. //快排
  37. void quickSort(int[] subTask,int lowSpace,int highSpace,int[] index){
  38. if(lowSpace<highSpace){//限制递归
  39. int low=lowSpace,high=highSpace;
  40. int insertIndex;//待插入位置
  41. int key=subTask[lowSpace];//关键字
  42. int table_key = index[lowSpace];//表索引虚拟关键字
  43. while(low<high){
  44. while(low<high&&subTask[high]>=key){
  45. high--;
  46. }
  47. if(low<high){
  48. swap(high,low,subTask);
  49. swap(high,low,index);
  50. }
  51. while(low<high&&subTask[low]<=key){
  52. low++;
  53. }
  54. if(low<high){
  55. swap(low,high,subTask);
  56. swap(low,high,index);
  57. }
  58. }
  59. insertIndex=low;
  60. subTask[insertIndex]=key;
  61. index[insertIndex]=table_key;//索引表也要变动
  62. if(insertIndex==lowSpace)
  63. quickSort(subTask,insertIndex+1,highSpace,index);//只用排高区
  64. else if(insertIndex==highSpace)
  65. quickSort(subTask,lowSpace,insertIndex-1,index);//只用排低区
  66. else {
  67. quickSort(subTask,lowSpace,insertIndex-1,index);
  68. quickSort(subTask,insertIndex+1,highSpace,index);
  69. }
  70. }
  71. }
  72. //建立索引表
  73. int[] creatTable(int n)
  74. {
  75. int[] table = new int[n];
  76. for (int i = 0; i < n; i++)
  77. {
  78. table[i] = i;
  79. }
  80. return table;
  81. }
  82. void scheduler(int[] task, int n, int[] system_task, int[] user_task){
  83. int[] table = creatTable(n);
  84. int index = findLine(task, 0, n - 1, 50, table);//以50为关键字划分
  85. //分别排序
  86. quickSort(task,0,index,table);
  87. quickSort(task,index+1,n-1,table);
  88. int len=0;//记录用户任务的长度,因为需要剔除大于255的数,所以长度不一定为n-index
  89. for(int i=0;i<n;i++){
  90. //系统任务[0,index)
  91. if(i<=index){
  92. system_task[i]=table[i];
  93. }
  94. //用户任务[index,n)
  95. else if(i>index){
  96. //剔除无效任务
  97. if(task[i]>=50&&task[i]<=255){
  98. user_task[i-index-1]=table[i];
  99. len++;
  100. }
  101. }
  102. }
  103. system_task[index+1]=-1;//结束
  104. user_task[len]=-1;
  105. }
  106. void printArr(int[] task,int n){
  107. for(int i=0;i<n;i++){
  108. Console.Write(task[i]+" ");
  109. }
  110. Console.WriteLine();
  111. }
  112. static void Main()
  113. {
  114. 任务分配 s = new 任务分配();
  115. int[] task={0, 30, 155, 1, 80, 300, 170, 40, 99};
  116. int[] system_task=new int[9];
  117. int[] user_task=new int[9];
  118. Console.WriteLine("原始任务为:");
  119. s.printArr(task,9);
  120. s.scheduler(task, 9, system_task, user_task);
  121. Console.WriteLine("系统任务为:");
  122. s.printArr(system_task, 9);
  123. Console.WriteLine("用户任务为:");
  124. s.printArr(user_task, 9);
  125. }
  126. }
  127. }
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace 控制台编程练习
{
    class 任务分配
    {
    //寻找关键字的分界线
    int findLine(int[] task,int lowSpace,int highSpace,int key,int[] table){
	    int low=lowSpace,high=highSpace;
	    while(low<high){
	
		    while(low<high&&task[high]>key){
			    high--;
		    }
		    if(low<high){
                swap(high, low, task);
                swap(high, low, table);
		    }
		    while(low<high&&task[low]<key){
			    low++;
		    }
		    if(low<high){
                swap( low,high ,task);
                swap(low, high, table);
		    }
		
	    }
	    return low;
   
}
//交换
void swap(int a,int b,int[] task){
	int tmp= task[a];
	task[a]=task[b];
	task[b]=tmp;
}
//快排
void quickSort(int[] subTask,int lowSpace,int highSpace,int[] index){
	
	if(lowSpace<highSpace){//限制递归
		int low=lowSpace,high=highSpace;
		int insertIndex;//待插入位置
		int key=subTask[lowSpace];//关键字
        int table_key = index[lowSpace];//表索引虚拟关键字
		while(low<high){
	
			while(low<high&&subTask[high]>=key){
				high--;
			}
			if(low<high){
				swap(high,low,subTask);
				swap(high,low,index);
			}
			while(low<high&&subTask[low]<=key){
				low++;
			}
			if(low<high){
				swap(low,high,subTask);
				swap(low,high,index);
			}
		
		}
		insertIndex=low;
		subTask[insertIndex]=key;
		index[insertIndex]=table_key;//索引表也要变动
		if(insertIndex==lowSpace)
			quickSort(subTask,insertIndex+1,highSpace,index);//只用排高区
		else if(insertIndex==highSpace)
			quickSort(subTask,lowSpace,insertIndex-1,index);//只用排低区
		else {
			quickSort(subTask,lowSpace,insertIndex-1,index);
			quickSort(subTask,insertIndex+1,highSpace,index);
		}
	}
}
//建立索引表
int[] creatTable(int n)
{
    int[] table = new int[n];
    for (int i = 0; i < n; i++)
    {
        table[i] = i;
    }
    return table;
}

void scheduler(int[] task, int n, int[] system_task, int[] user_task){
    int[] table = creatTable(n);
    int index = findLine(task, 0, n - 1, 50, table);//以50为关键字划分
	//分别排序
	quickSort(task,0,index,table);
	quickSort(task,index+1,n-1,table);
	int len=0;//记录用户任务的长度,因为需要剔除大于255的数,所以长度不一定为n-index
	for(int i=0;i<n;i++){
		//系统任务[0,index)
		if(i<=index){
			system_task[i]=table[i];
		}
		//用户任务[index,n)
		else if(i>index){
			//剔除无效任务
			 if(task[i]>=50&&task[i]<=255){
				user_task[i-index-1]=table[i];
				len++;
		     }
		}
	}
	system_task[index+1]=-1;//结束
	user_task[len]=-1;
}

void printArr(int[] task,int n){
	for(int i=0;i<n;i++){
	  Console.Write(task[i]+" ");
	}
    Console.WriteLine();
}

    static void Main()
    {
        任务分配 s = new 任务分配();
        int[] task={0, 30, 155, 1, 80, 300, 170, 40, 99};
	    int[] system_task=new int[9];
	    int[] user_task=new int[9];
        Console.WriteLine("原始任务为:");
        s.printArr(task,9);
        s.scheduler(task, 9, system_task, user_task);
        Console.WriteLine("系统任务为:");
        s.printArr(system_task, 9);
        Console.WriteLine("用户任务为:");
        s.printArr(user_task, 9);
    }
  }
}


输出:

原始任务为:
0 30 155 1 80 300 170 40 99
系统任务为:
0 3 1 7 -1 0 0 0 0
用户任务为:
4 8 2 6 -1 0 0 0 0
请按任意键继续. . .

10.奇偶插入排序

题目:
对一个数组,将数组中偶数从大到小排序,奇数从小到大排序,奇数和偶数交叉着放且输出数组第一位放奇数若奇数和偶数不等长,则把剩下的直接放到数组中。
思路:
将奇数和偶数元素分别存放,然后分别排序,最后一起交叉填充(覆盖)到原数组。

C/C++实现如下:


  1. #include<stdio.h>
  2. #include<malloc.h>
  3. #define DEFAULT 0
  4. #define low_to_high 0//由小到大
  5. #define high_to_low 1//由大到小
  6. using namespace std;
  7. //折半插入排序
  8. void halfSort(int *a,int n,int type){
  9. for(int i=1;i<n;i++){
  10. int high=i-1;
  11. int low=0;
  12. int mid=(high+low)/2;
  13. int key=a[i];//待排关键字
  14. //寻找位置
  15. if(type==low_to_high){
  16. while(low<=high){
  17. if(a[mid]<key)
  18. low=mid+1;
  19. else
  20. high=mid-1;
  21. mid=(low+high)/2;
  22. }
  23. }
  24. else{
  25. while(low<=high){
  26. if(a[mid]<key)
  27. high=mid-1;
  28. else
  29. low=mid+1;
  30. mid=(low+high)/2;
  31. }
  32. }
  33. //插入位置在high+1,全体移动a[high+1]...a[i]
  34. for(int j=i;j>high+1;j--){
  35. a[j]=a[j-1];
  36. }
  37. a[high+1]=key;
  38. }
  39. }
  40. void print(int *a,int n){
  41. for(int i=0;i<n;i++){
  42. printf("%d ",*(a+i));
  43. }
  44. /*while(*a!='\0'){
  45. printf("%d ",*a++);
  46. }*/
  47. printf("\n");
  48. }
  49. void oddAndEvenSort(int a[],int n){
  50. int odd[10]={0};
  51. int even[10]={0};
  52. int evenCount=0;//偶数个数
  53. int oddCount=0;
  54. for(int i=0;i<n;i++){
  55. if(a[i]%2==0){
  56. even[evenCount]=a[i];
  57. evenCount++;
  58. }
  59. else{
  60. odd[oddCount]=a[i];
  61. oddCount++;
  62. }
  63. }
  64. halfSort(odd,oddCount,low_to_high);
  65. halfSort(even,evenCount,high_to_low);
  66. if(oddCount==0){
  67. print(even,evenCount);
  68. }
  69. else if(evenCount==0){
  70. print(odd,oddCount);
  71. }
  72. else if(oddCount<evenCount){
  73. for(int i=0;i<oddCount;i++){
  74. a[2*i]=odd[i];
  75. a[2*i+1]=even[i];
  76. }
  77. for(int j=oddCount;j<n;j++){//剩余偶数补全
  78. a[j+oddCount]=even[j];
  79. }
  80. print(a,n);
  81. }
  82. else if(oddCount==evenCount){
  83. for(int i=0;i<oddCount;i++){
  84. a[2*i]=odd[i];
  85. a[2*i+1]=even[i];
  86. }
  87. print(a,n);
  88. }
  89. else if(oddCount>evenCount){
  90. for(int i=0;i<evenCount;i++){
  91. a[2*i]=odd[i];
  92. a[2*i+1]=even[i];
  93. }
  94. for(int j=evenCount;j<n;j++){//剩余奇数补全
  95. a[j+evenCount]=odd[j];
  96. }
  97. print(a,n);
  98. }
  99. }
  100. void main(){
  101. int a1[]={2,4,6,8,10,12,14,16,18,1};
  102. oddAndEvenSort(a1,10);
  103. int a2[]={2,4,6,8,10,1,3,5,7,9};
  104. oddAndEvenSort(a2,10);
  105. int a3[]={2,4,6,1,3,5,7,9,11,13};
  106. oddAndEvenSort(a3,10);
  107. }
#include<stdio.h>
#include<malloc.h>
#define DEFAULT 0
#define low_to_high 0//由小到大
#define high_to_low 1//由大到小
using namespace std;

//折半插入排序
void halfSort(int *a,int n,int type){
	for(int i=1;i<n;i++){
		int high=i-1;
		int low=0;
		int mid=(high+low)/2;
		int key=a[i];//待排关键字
		//寻找位置
		if(type==low_to_high){
			while(low<=high){
				if(a[mid]<key)
					low=mid+1;
				else
					high=mid-1;
				mid=(low+high)/2;
			}
		}
		else{
			while(low<=high){
				if(a[mid]<key)
					high=mid-1;
				else
					low=mid+1;
				mid=(low+high)/2;
			}
		}
		//插入位置在high+1,全体移动a[high+1]...a[i]
		for(int j=i;j>high+1;j--){
			a[j]=a[j-1];
		}
		a[high+1]=key;
	}
}

void print(int *a,int n){
	for(int i=0;i<n;i++){
		printf("%d ",*(a+i));
    }
	/*while(*a!='\0'){
		printf("%d ",*a++);
	}*/
	printf("\n");
}


void oddAndEvenSort(int a[],int n){
	int odd[10]={0};
	int even[10]={0};
	int evenCount=0;//偶数个数
	int oddCount=0;
	for(int i=0;i<n;i++){
		if(a[i]%2==0){
			even[evenCount]=a[i];
		
			evenCount++;
		}
		else{
			odd[oddCount]=a[i];
			
			oddCount++;
		}
	}
	
	halfSort(odd,oddCount,low_to_high);
	halfSort(even,evenCount,high_to_low);
	if(oddCount==0){
		print(even,evenCount);
	}
	else if(evenCount==0){
		print(odd,oddCount);
	}
	else if(oddCount<evenCount){
		for(int i=0;i<oddCount;i++){
			a[2*i]=odd[i];
			a[2*i+1]=even[i];
		}
		for(int j=oddCount;j<n;j++){//剩余偶数补全
			a[j+oddCount]=even[j];
		}
		print(a,n);
	}
	else if(oddCount==evenCount){
		for(int i=0;i<oddCount;i++){
			a[2*i]=odd[i];
			a[2*i+1]=even[i];
		}
		print(a,n);
	}
		
	else if(oddCount>evenCount){
		for(int i=0;i<evenCount;i++){
			a[2*i]=odd[i];
			a[2*i+1]=even[i];
		}
		for(int j=evenCount;j<n;j++){//剩余奇数补全
			a[j+evenCount]=odd[j];
		}
		print(a,n);
	}


}

void main(){
	int a1[]={2,4,6,8,10,12,14,16,18,1};
	oddAndEvenSort(a1,10);
	int a2[]={2,4,6,8,10,1,3,5,7,9};
	oddAndEvenSort(a2,10);
	int a3[]={2,4,6,1,3,5,7,9,11,13};
	oddAndEvenSort(a3,10);

}


输出:

1 18 16 14 12 10 8 6 4 2
1 10 3 8 5 6 7 4 9 2
1 6 3 4 5 2 7 9 11 13

总结:又没仔细看题,偶数元素是从大到小,奇数是从小到大排序,题目虽简,但也须仔细认真,切记。

 
 
 
高级题样题:地铁换乘
描述:已知2条地铁线路,其中A为环线,B为东西向线路,线路都是双向的。经过的站点名分别如下,两条线交叉的换乘点用T1、T2表示。编写程序,任意输入两个站点名称,输出乘坐地铁最少需要经过的车站数量(含输入的起点和终点,换乘站点只计算一次)。 地铁线A(环线)经过车站:A1 A2 A3 A4 A5 A6 A7 A8 A9 T1 A10 A11 A12 A13 T2 A14 A15 A16 A17 A18 地铁线B(直线)经过车站:B1 B2 B3 B4 B5 T1 B6 B7 B8 B9 B10 T2 B11 B12 B13 B14 B15
输入:输入两个不同的站名
输出:输出最少经过的站数,含输入的起点和终点,换乘站点只计算一次
输入样例:A1 A3
输出样例:3
答案参考:
1. import java.util.*;
2.
3.
4. public class Main {
5.
6. private static int INVALID_POSITION = 255;
7.
8. class BusLine {
9. String busstop[];
10. String lineName;
11.
12. public BusLine(String line) {
13. String[] stops = line.split(" ");
14. this.busstop = new String[stops.length];
15. for (int i = 0; i < stops.length; i++) {
16. this.busstop = stops;
17. lineName = stops[0].substring(0, 1);
18. }
19. }
20.
21. /* get the stop position from the line */
22. int getStopPosition (String point) {
23. for (int i = 0; i < busstop.length; i++) {
24. if (busstop.equals(point)) {
25. return i;
26. }
27. }
28. return INVALID_POSITION;
29. }
30.
31. int getDistance(String pointA, String pointB) {
32. int positionA = 0;
33. int positionB = 0;
34. int len = 0;
35.
36. positionA = getStopPosition(pointA);
37. positionB = getStopPosition(pointB);
38.
39. if (positionA != INVALID_POSITION && positionB != INVALID_POSITION) {
40. len = Math.abs(positionA - positionB) + 1;
41. if (lineName.equals("A") && len > (busstop.length - len + 2)) {
42. len = (busstop.length - len + 2);
43. }
44.
45. return len;
46. }
47.
48. return INVALID_POSITION;
49. }
50.
51. }
52.
53.
54. public int getRide(String pointA, String pointB) {
55. int i = 0;
56. int min = 255;
57. BusLine lineA = new BusLine("A1 A2 A3 A4 A5 A6 A7 A8 A9 T1 A10 A11 A12 A13 T2 A14 A15 A16 A17 A18");
58. BusLine lineB = new BusLine("B1 B2 B3 B4 B5 T1 B6 B7 B8 B9 B10 T2 B11 B12 B13 B14 B15");
59.
60. int[] way = {255, 255, 255, 255, 255, 255, 255, 255};
61.
62. way[0] = lineA.getDistance(pointA, pointB);
63. way[1] = lineB.getDistance(pointA, pointB);
64.
65. way[2] = lineA.getDistance(pointA, "T1") + lineB.getDistance(pointB, "T1") - 1;
66. way[3] = lineB.getDistance(pointA, "T1") + lineA.getDistance(pointB, "T1") - 1;
67.
68. way[4] = lineA.getDistance(pointA, "T2") + lineB.getDistance(pointB, "T2") - 1;
69. way[5] = lineB.getDistance(pointA, "T2") + lineA.getDistance(pointB, "T2") - 1;
70.
71. way[6] = lineB.getDistance(pointA, "T1") + lineB.getDistance(pointB, "T2") + lineA.getDistance("T1", "T2") - 2;
72. way[7] = lineB.getDistance(pointA, "T2") + lineB.getDistance(pointB, "T1") + lineA.getDistance("T1", "T2") - 2;
73.
74. for (i = 0; i < 7; i++) {
75. if (min > way) {
76. min = way;
77. }
78. }
79.
80. return min;
81. }
82.
83. public static void main(String[] args) {
84. Main m = new Main();
85. Scanner cin = new Scanner(System.in);
86. String inputStr = cin.nextLine();
87. String stops[] = inputStr.split(" ");
88.
89. System.out.println(m.getRide(stops[0], stops[1]));
90. }
91.
92. }
其实后来发现整个过程下来还是有点紧张的。数组、链表、指针、字符串、循环、枚举、排序等内容基本上都考察到了。大家借鉴下吧。我的难度比其他同学难度大了些,最后一个当时没测试通过,回来才调过。做对了两道。加油吧,毕业季里相互分享下资料,互惠互利。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

常见算法题(包括华为机试题) 的相关文章

  • ⛳ TCP 协议面试题

    目录 TCP 协议面试题 一 为什么关闭连接的需要四次挥 建 连接却只要三次握 呢 二 为什么连接建 的时候是三次握 可以改成两次握 吗 三 为什么主动断开 在TIME WAIT状态必须等待2MSL的时间 四 如果已经建 了连接 但是Cli

随机推荐

  • PyTorch 官方教程:撸一个神经网络

    本文为 PyTorch 官方教程中 如何构建神经网络 基于 PyTorch 专门构建神经网络的子模块 torch nn 构建一个简单的神经网络 完整教程运行 codelab torch nn 文档 神经网络由对数据执行操作的层 模块组成 t
  • PaddleDetection重磅升级!PP-YOLOE、PP-PicoDet云边端一网打尽!

    目标检测作为计算机视觉领域的顶梁柱 不仅可以独立完成车辆 商品 缺陷检测等任务 也是人脸识别 视频分析 以图搜图等复合技术的核心模块 在自动驾驶 工业视觉 安防交通等领域的商业价值有目共睹 正因如此 YOLOv5 YOLOX PP YOLO
  • 从Java到Go:构建一个任务调度器和队列管理系统

    目录 1 任务调度器和队列管理的基本概念 2 Java和Go的基本差异 2 1 语法差异
  • osg::ref_ptr<osg::Image> image = osgDB::readImageFile(fileName); image指针为空

    前言 使用 OpenSceneGraph Quick Start Guide 中文版及源码 里面的一个例子TextureMapping 在我本机上运行没有问题 但拷贝到公司电脑 发现总是运行异常 无法读取纹理图片 调试到136行 image
  • lua的pcall

    对于大多数应用而言 我们无须在Lua代码中做任何错误处理 应用程序本身会负责处理这类问题 所有Lua语言的行为都是由应用程序的一次调用而触发的 这类调用通常是要求Lua语言执行一段代码 如果执行中发生了错误 那么调用会返回一个错误代码 以便
  • AcWing 196. 质数距离 二次筛法

    题 想求231 1范围的质数距离 那么我们可以求5e4范围中的所有质数 然后这些质数可以组成2 231 1中的所有合数 打表求5e4范围中的质数 用类似埃氏筛的方法把l到r的所有质数筛出来 由于差值不会超过 106 可以O n 扫描一遍求距
  • pytorch,mmdetection的安装以及注意事项

    如题 记录一下pytorch mmdetection的安装 以及注意事项 conda 基础操作 创建 name mmlab conda create n mmlab python 3 8 删除 conda remove n mmlab al
  • 数学建模-启发式算法-蚁群算法

    文章目录 蚁群算法 算法原理 算法特点 算法步骤 流程图 代码 蚁群算法 蚁群算法 由Marco Dorigo于1992年在他的博士论文中提出 是一种灵感来源于蚂蚁在寻找食物过程中发现路径的行为 用来在图中寻找优化路径的算法 算法原理 蚂蚁
  • 单例模式中的懒汉模式和饿汉模式是什么?

    一 懒汉模式 顾名思义 他是一个懒汉 他不愿意动弹 什么时候需要吃饭了 他就什么时候开始想办法搞点食物 即懒汉式一开始不会实例化 什么时候用就什么时候new 才进行实例化 二 饿汉模式 顾名思义 他是一个饿汉 他很勤快就怕自己饿着 他总是先
  • sqldeveloper 格式化(美化)sql语句快捷键

    1 Ctrl A 全选需要格式化的sql 2 Ctrl F7 格式化
  • C语言文件操作(1)

    目录 一 为什么使用文件 二 什么是文件 2 1 程序文件 2 2 数据文件 2 3 文件名 三 文件的打开和关闭 3 1 文件指针 3 2 文件的打开和关闭 四 文件的顺序读写 4 1 对比一组函数 一 为什么使用文件 我们前面学习 结构
  • UVA 1601 The Morning after Halloween (BFS/双向BFS)

    单向BFS 1150ms include
  • opencv-bayes模型训练以及加载

    此代码适用于opencv 数据集分开训练数据集和测试数据集合 训练模型代码 Ptr
  • 分享5个免费的Python学习网站,抓紧收藏吧~

    最近有好多人说刚开始学习 有哪些免费的学习网站可以自学一下 于是 趁着空闲的时间在各大网站上面梳理了一下 找出了5个比较好的学习网站 并且都是免费的 比较适合初学者了解一些基础语法 解决BUG问题 如果是大佬的话了解一下就行了 废话不多说了
  • 基于RRT算法的避障路径规划(MATLAB代码)

    基于RRT算法的避障路径规划 MATLAB代码 路径规划是机器人导航和自主移动中的关键问题之一 Rapidly exploring Random Trees RRT 算法是一种经典的随机采样路径规划算法 它通过随机采样和不断扩展树结构来搜索
  • Java英文日期格式转换yyyy-MM-dd格式

    我们在后端的开发过程中会经常跟日期相关的类型打交道 不过我们大多数在开发过程中遇到的格式都是基本的 年 月 日 yyyy MM dd 格式 当然 这种格式的日期我们都可以用Java自带的SimpleDateFormat类自带的转换方法来进行
  • Animate 2021 for Mac(an 2021中文版) v21.0.1中文直装版

    全新的adobe animate2021版本更加的引入注目 比如经过修改后的资产面板允许您在新的 默认 和 自定义 选项卡中查找 组织和管理资产 并且可通过组合各种资产快速创建炫酷的动画 从而减轻了以往的逐个创建动画效果 Animate 2
  • 关于moment时区处理问题,指定时间转换特定时区

    如题网上一堆复制粘贴让使用timezone插件的文章 查了十几分钟 真是浪费生命 垃圾文章太多 如果只想转换某个时间而已 是不需要使用timezone插件的 这个插件一用可能全局的时区就变了 问题就大了 只转换某几个时间的时区解决办法是mo
  • echart时间轴设置详解

    timeline x center 时间轴X轴方向位置设置 y bottom 时间轴Y轴方向位置设置 width 80
  • 常见算法题(包括华为机试题)

    一 维护O 1 时间查找最大元素的栈 问题描述 一个栈stack 具有push和pop操作 其时间复杂度皆为O 1 设计算法max操作 求栈中的最大值 该操作的时间复杂度也要求为O 1 可以修改栈的存储方式 push pop的操作 但是要保