致精团队笔试题2道

 
A、两个数组,一个长度n,一个长度2n但是只有前n个数字有效。他们都是排序的。现在要把第一个数组合并到第二个数组里面并且使得结果仍然保持排序,求O(n)算法
void merge(int* a , int* b , int n);
 
B、已知两个单向链表,尾部是共享的,看起来是Y字形,现在给出两个链表头,求出相交的第一个节点,要求O(n)
struct node{node* next;};

      node* find_conflict(node* a , node* b);                                                                                                     

致精团队给出的思路:图示如下,题A

A=1 3 5

B=2 6 10 X X X

init:

 A=1 3 5

            ^lastA
 B=2 6 10 X X X
             ^lastB  *lastR
1:
 A=1 3 5
            ^
 B=2 6 X X X 10
          ^        *
2:
 A=1 3 5
            ^
 B=2 X X X 6 10
      ^         *
3:
 A=1 3 X
         ^
 B=2 X X 5 6 10
       ^    *
4:
 A=1 X X
      ^
 B=2 X 3 5 6 10
       ^ *
5:
 A=1 X X
    ^
 B=X 2 3 5 6 10
 ^ *
6:
 A=X X X
 ^
 B=1 2 3 5 6 10
 ^*
想法:此答案来源于 merge sort 的每个迭代的最后一步
程序如下:
#include <iostream>
#include <string>
using namespace std;
void sort(int* A , int* B , int lenA)
{
 int indexLastA = lenA - 1;//数组A的最后一个有效元素下标
 int indexLastB = lenA - 1;//数组B的最后一个有效元素下标
 int indexLastBB = 2*lenA - 1;//数组B的最后一个元素下标
 //每次拿出A和B的最后一个没被放入结果的元素做比较,将大的那个放入结果的最后一个空闲位置
 while (indexLastBB >= 0)
 {
  if (indexLastA >= 0)
  {
   if (indexLastB >= 0)
   {
    if (A[indexLastA] > B[indexLastB])
    {
     B[indexLastBB--] = A[indexLastA--];
    }
    else
    {
     B[indexLastBB--] = B[indexLastB--];
    }
   }
   else
   {
    B[indexLastBB--] = A[indexLastA--];
   }
  }
  else
  {
   if (indexLastB >= 0)
   {
    B[indexLastBB--] = B[indexLastB--];
   }
  }
 }
}
int main()
{
 int A[3] = {1,3,5};
 int B[6] = {2,6,10};
 int len = sizeof(A)/sizeof(A[0]);
 cout<<"Array A:";
 for (int i=0; i<len; i++)
 {
  cout<<A[i]<<' ';
 }
 cout<<endl<<"Array B:";
 for (int j=0; j<len; j++)
 {
  cout<<B[j]<<' ';
 }
 sort(A,B,len);
 cout<<endl<<"After sort Array B:";
 for (int k=0; k<2*len; k++)
 {
  cout<<B[k]<<' ';
 }
 return 0;
}
题B图示:

图示:

假设a b如下

A:1 2 3 4

          7 8 9 10

B:    5 6

链表A=1 2 3 4 7 8 9 10

链表B=5 6 7 8 9 10

第一个交点明显是7。根据以上算法

 

第一步:算出lenA=8

第二步:算出lenB=6

第三步,由于lenA>lenB,于是让A跳过lenA-lenB个节点,此时A指向3

第四步,依次比较:

   5!=3

   6!=4

   7==7 ,返回 7
程序如下:
#include <iostream>
#include <malloc.h>
using namespace std;
struct List
{
 int Number;
 struct List *Next;
};
typedef struct List Node;
typedef Node *Link;
int LA[] = {1,2,3,4,7,8,9,10};
int LB[] = {5,6,7,8,9,10};
void Free_List(Link Head)//释放链表
{
 Link Pointer;
 while (Head != NULL)
 {
  Pointer = Head;
  Head = Head->Next;
  free(Pointer);
 }
}
void Print_List(Link Head)//打印链表
{
 Link Pointer;
 Pointer = Head;
 while(Pointer != NULL)
 {
  cout<<Pointer->Number<<' ';
  Pointer = Pointer->Next;
 }
 cout<<endl;
}
Link Create_List(Link Head,int *L,int Max)//创建链表
{
 Link New;
 Link Pointer;
 int i;
 Head = (Link)malloc(sizeof(Node));
 if (Head == NULL)
 {
  cout<<"Memory allocate Failure!"<<endl;
 }
 else
 {
  Head->Number = L[0];//定义首节点
  Head->Next = NULL;
  Pointer = Head;
  for (i=1; i<Max; i++)
  {
   New = (Link)malloc(sizeof(Node));
   New->Number = L[i];
   New->Next = NULL;
   Pointer->Next = New;//将新节点串连在原链表尾端
   Pointer = New;//链表尾端节点为新节点
  }
 }
 return Head;
}
int Link_length(Link Head)//求链表长度
{
 int len = 0;
 Link Pointer = Head;
 while (Pointer)
 {
  len++;
  Pointer = Pointer->Next;
 }
 return len;
}
int Find_conflict(Link A , Link B)
{
 int lenA = Link_length(A);
 int lenB = Link_length(B);
 if (lenA > lenB)//跳过比较长的链表的|lenA-lenB|个节点
 {
  while((lenA--) > lenB)
  {
   A = A->Next;
  }
 }
 else
 {
  while ((lenB--) > lenA)
  {
   B = B->Next;
  }
 }
 while (A)//一个一个配对比较,如果发现相等则返回节点。此时A和B一样长
 {
  if (A->Number == B->Number)
  {
   return A->Number;
  }
  else
  {
   A = A->Next;
   B = B->Next;
  }
 }
 return 0;//找不到交点,返回空
}
int main()
{
 Link Head = NULL;
 Link Head1 = NULL;
 Link Head2 = NULL;
 Head1 = Create_List(Head1,LA,sizeof(LA)/sizeof(LA[0]));
 Head2 = Create_List(Head2,LB,sizeof(LB)/sizeof(LB[0]));
 if (Head1 != NULL && Head2 != NULL)
 {
  cout<<"Link A and Link B :"<<endl;
  Print_List(Head1);
  Print_List(Head2);
 }
 cout<<"The first conflict element is : "<<Find_conflict(Head1,Head2)<<endl;
 Free_List(Head1);
 Free_List(Head2);
 return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值