数据结构面试题1

  算法+数据结构=编程

  什么是数据结构?

 

  简单地说,数据结构是以某种特定的布局方式存储数据的容器。这种“布局方式”决定了数据结构对于某些操作是高效的,而对于其他操作则是低效的。首先我们需要理解各种数据结构,才能在处理实际问题时选取最合适的数据结构。

  为什么我们需要数据结构?

   数据是计算机科学当中最关键的实体,而数据结构则可以将数据以某种组织形式存储,因此,数据结构的价值不言而喻。无论你以何种方式解决何种问题,你都需要处理数据——无论是涉及员工薪水、股票价格、购物清单,还是只是简单的电话簿问题。数据需要根据不同的场景,按照特定的格式进行存储。有很多数据结构能够满足以不同格式存储数据的需求。

  常见的数据结构

 

  • 数组

  • 队列

  • 链表

  • 字典树(这是一种高效的树形结构,但值得单独说明)

  • 散列表(哈希表)

    数组:

    数组是最简单、也是使用最广泛的数据结构。栈、队列等其他数据结构均由数组演变而来。数组有两种类型,一维数组和多维数组。

    数组的基本操作:

 

  • Insert——在指定索引位置插入一个元素

  • Get——返回指定索引位置的元素

  • Delete——删除指定索引位置的元素

  • Size——得到数组所有元素的数量

面试中关于数组的常见问题:

 

  • 寻找数组中第二小的元素

  • 找到数组中第一个不重复出现的整数

  • 合并两个有序数组

  • 重新排列数组中的正值和负值

 

解答:

#include <stdio.h>
 
int FindSecondBiggest(int *v, int len)
{
    if (v == NULL || len < 2) {
        return 0xfffffff;
    }
 
    int i, max = v[0], second = v[1];
    if (max < second) {
        max = v[1];
        second = v[0];
    }
    for (i = 2; i < len; ++ i) {
        if (v[i] > max) {
            second = max;
            max = v[i];        
        } else if (v[i] > second) {
            second = v[i];
        }
    }
    return second;
}
 
int FindSecondLeast(int *v, int len)
{
    if (v == NULL || len < 2) {
        return 0xffffffff;
    }
 
    int i, min = v[0], second = v[1];
    if (min > second) {
        min = v[1];
        second = v[0];
    }
    for (i = 2; i < len; ++ i) {
        if (v[i] < min) {
            second = min;
            min = v[i];
        } else if (v[i] < second) {
            second = v[i];
        }
    }
    return second;
}
 
int main()
{
    int v[] = {1,2,3};
    int len = sizeof(v) / sizeof(v[0]);
    printf("SecondBiggest = %d\n", FindSecondBiggest(v, len));
    printf("SecondLeast = %d\n", FindSecondLeast(v, len));
    return 0;
}

方法1 蛮力查找 主要思想:对于数组中的第i个数,查找i+1到末尾的所有整数,一个数如果出现了两次就可以在第一次后面找到第二次出现的数,时间复杂度 O(n^2)。

#include<stdio.h>
 
void find_duplicates(int* num, int start, int end){
    int size = end-start+1;
    int i = 0;
    int j = 0;
    for(i=0; i<size; i++){
        for(j=i+1; j<size; j++){
            if(num[i] == num[j])
                printf("%d\n", num[i]);
        }
    }
 
}
 
void main(){
 
    int A[]={5,2,4,3,1,3,2};
    find_duplicates(A, 0, 6);
}

方法2:异或(xor)

主要思想:由于限定了是1到n之间的数,且每个数至少出现一次,可以先把数组中的所有整数异或一遍,然后把结果再和1、2、3、、、n异或一遍,这样就得到了那两个重复出现的整数的异或结果 x。接下来主要是想办法把它们两给区分开来,对于异或结果x,它的二进制表示有0和1构成,有异或的性质可知,二进制表示的x中那些出现0的位是两个重复数对应位置均为1或者0的结果,而出现1的位则只有一种可能:两个数对应位置一个是0,一个是1。借助这个特点,我们就可以选取一个特定的位置(x的那个位置是1)把原来的数组分成两个部分,部分I对应那个特定位置为1的数,部分II对应那个特定位置为0的数,这样就把问题转化为:在每个部分查找一个重复出现的数字。时间复杂度 O(n)。

#include<stdio.h>
 
void find_duplicates(int* num, int start, int end){
    int size = end-start+1;
    int bit_flag = 0;
    int i=0;
    for(i=0; i<size; i++){
        bit_flag ^= num[i];
    }
     
    for(i=1; i<size-1; i++){
        bit_flag ^= i;
    }
     
    int division_bit = bit_flag & ~(bit_flag-1);
 
    int a = 0;
    int b = 0;
    for(i=0; i<size; i++){
        if(num[i] & division_bit)
            a ^= num[i];
        else
            b ^= num[i];
    }
    for(i=1; i<size-1; i++){
        if(i & division_bit)
            a ^= i;
        else
            b ^= i;
    }
    printf("duplicate numbers a=%d \t b=%d\n", a, b);
}
 
void main(){
 
    int A[]={5,2,4,3,1,3,2};
    find_duplicates(A, 0, 6);
     
}

给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 使得 num1 成为一个有序数组。

  • 初始化 nums1 和 nums2 的元素数量分别为 m 和 n
  • 你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。
  • class Solution {
    public:
        void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
            int num[m+n];//新建一个数组,对nums1和nums2排序,排完序赋值给nums1
            int i = 0,j = 0,k = 0;
            while(i<m && j<n){
                if(nums1[i] <= nums2[j])
                    num[k++] = nums1[i++];
                else
                    num[k++] = nums2[j++];
            }
            while(i < m) num[k++] = nums1[i++];
            while(j < n) num[k++] = nums2[j++];
            copy(num,num+m+n,nums1.begin());
        }
    };
    

  • 设定两个计数器begin、end,其中begin始终指向数组中的第一个负数,end始终指向位于begin之后的第一个正数。然后把begin、end之间的数字往后移,即让原来end位置的数字移动到begin位置,循环上述过程。直到end大于数组长度即break。

  • 设两个指针positive, negative,初始指向数组最后一个元素,然后从后往前遍历数组,positive每次指向第一个满足positive<negative的正数,negative指向最后一个负数,然后将positive+1到negative的元素往前移,将positive移至negative位置。循环上述过程,直至positive<0时。

#include <stdio.h>
 
/*
* Author : Tian Mo
*
* Date   : 2013-06-22 19:37
*
* Locate : Baidu PS, Beijing
*/
 
int SepPositiveNegative(int *v, const unsigned int len)
{
	/* ASSERT ERROR */
	if (NULL == v || len <= 0)
	{
		return -1;
	}
 
	int i,j,k,begin,end,temp;
 
	for(i = 0; i < len; ++ i)
	{
		/* From current data start compute */
		k = i;
		while(v[k] >= 0)
		{
			++ k;
		}
		/* Record the first negative always */
		begin = k;
	
		while(v[k] < 0)
		{
			++ k;
		}
		/* Record the first positive which after the first negative always */
		end = k;
 
		/* if the last negative beyond the length of array v, must be break */
		if (end > len - 1)
		{
			break;
		}
		
		/* Move the first positive which after the first negative to		\
		   the place where the first negative begin  */
		temp = v[end];
		for(j = end; j > begin; -- j)
		{
			v[j] = v[j - 1];
		}
		v[begin] = temp;		
	}
	
	return 0;
}
 
void print(const int *v, const unsigned int len)
{
	printf("Items AS : ");
	unsigned int i;
	for (i = 0; i < len; ++ i)
	{
		printf("%2d ", v[i]);
	}
	printf("\n");
}
 
int main()
{
	int v[] = {-5, 2, -3, 4, -8, -9, 1, 3, -10};
	//int v[] = {-5, 2, -3, 4, -8, -9, 1, 3, 12, 15, 19, -7,-2,};
	//int v[] = {-1, -3, -5, -7, 1, 3, 5, 7, 9};
	const len = sizeof(v) / sizeof(v[0]);
 
	print(v, len);
 
	if (-1 != SepPositiveNegative(v, len))
	{
		print(v, len);
	}
	else 
	{
		printf("Compute Data Error.\n");
	}
	
	return 0;
}

 

猜你喜欢

转载自blog.csdn.net/Zz8474/article/details/82927772