【剑指Offer】鸟瞰50题之31 - 40题

面试题31连续子数组的最大和 

面试题32从1到n整数中1出现的次数 

面试题33把数组排成最小的数 

面试题34丑数 

面试题35第一个只出现一次的字符 

面试题36数组中的逆序对

面试题37两个链表的第一个公共结点 

面试题38数字在排序数组中出现的次数 

面试题39 二叉树的深度  

面试题40数组中只出现一次的数字 

/*******************************************************/

面试题31连续子数组的最大和 ,输入一个数组,数组里面有正数,也有负数。求连续数的最大值

实现如下:

int MaxSum(int num[], int length)
{
	int CurrentSum = 0;
	int iResult = 0x80000000;
	
	if (num == NULL || length < 0)
	{
		return 0;/* invalid */
	}
	
	for (int i = 0; i < length; i++)
	{
		
		if (CurrentSum <= 0)
		{
			CurrentSum = num[i];
		}
		else
		{
			CurrentSum += num[i];
		}

		if (CurrentSum > iResult)
			iResult = CurrentSum;
	}
	return iResult;
}

面试题32从1到n整数中1出现的次数 ,输入一个N,求1到N所有的整数中1出现的次数

实现如下:

#include <iostream>

int CountNum(int n)
{
	int iCurrentNum = 0;/* 当前位的数 */
	int iNTemp = n;
	int iResult = 0;
	int iBase = 1;  /* 个位 */
	int iRemain = 0;

	if (n <= 0)
	{
		return 0;
	}
	
	while (iNTemp > 0)
	{
		iCurrentNum = iNTemp % 10;
		iNTemp = iNTemp/10;

		if (iCurrentNum > 1)
		{
			iResult+= (iNTemp + 1)*iBase;
		}
		else if (iCurrentNum == 1)
		{
			iResult+= (iNTemp)*iBase + iRemain + 1;
		}
		else if (iCurrentNum == 0)
		{
			
			iResult+= (iNTemp)*iBase;
		}

		
		iRemain += iCurrentNum*iBase; /* 先计算剩余数大小*/
		iBase = iBase*10; /**然后计算下次base位*/ 
	}

	return iResult;
}

int main()
{
	printf("%d\n",CountNum(11));
}


面试题33把数组排成最小的数 

实现如下:

#include <iostream>
#define MAX_NUM_LENGTH 10

int compare(const void *str1, const void *str2)
{
	char str1Temp[MAX_NUM_LENGTH*2 +1];
	char str2Temp[MAX_NUM_LENGTH*2 +1];

	strcpy(str1Temp, (const char*)str1);
	strcat(str1Temp, (const char*)str2);
	
	strcpy(str2Temp, (const char*)str2);
	strcat(str2Temp, (const char*)str1);

	return strcmp(str1Temp,str2Temp);
	
}
void GetMinNum(int num[], int length)
{
	char **numStr = (char **)malloc(length + 1);
	for (int i = 0; i < length; i++)
	{
		numStr[i] = (char *)malloc(MAX_NUM_LENGTH +1);
		sprintf(numStr[i],"%d",num[i]);
	}
	qsort(numStr,length,sizeof(char *),compare);

	for (int i = 0; i < length; i++)
	{
		printf("%s",numStr[i]);
	}

    /* 释放内存 */
	for (int i = 0; i < length; i++)
	{
		free(numStr[i]);
	}
	free(numStr);

}

int main()
{
	int num[] = {1,234,341};
	GetMinNum(num, 3);
}


面试题34丑数 

实现如下:

#include <iostream>
#define MAX_NUM_LENGTH 10

int min(int a, int b, int c)
{
	int min = (a>b)?b:a;
	min = (min > c)? c:min;
	
	return min;
}
/* 只能被2、3、5整除的 */
int GetUglyNum(int n)
{
	/* 创建一个n个元素的数组 */
	int UglyNum[n];
	int p2 = 0;
	int p3 = 0;
	int p5 = 0;
	int NextIndex = 1;
	UglyNum[0] = 1;

	while(NextIndex < n)
	{
		UglyNum[NextIndex] = min(UglyNum[p2]*2, UglyNum[p3]*3 ,UglyNum[p5]*5);
		
		while(UglyNum[p2]*2 <= UglyNum[NextIndex])
		{
			p2++;			
		}
		while(UglyNum[p3]*3 <= UglyNum[NextIndex])
		{
			p3++;			
		}
		while(UglyNum[p5]*5 <= UglyNum[NextIndex])
		{
			p5++;			
		}

		NextIndex++;
	}

	return UglyNum[NextIndex - 1];
}

int main()
{
	printf("%d\n",GetUglyNum(3));
	
}


面试题35第一个只出现一次的字符 

实现如下:

#include <iostream>
#define VOS_OK  0
#define VOS_ERR 1


/* 只能被2、3、5整除的 */
int GetFirstChar(char *str, char *result)
{
	unsigned int hashNum[256] = {0};
	char *p;
	
	if (str == NULL)
	{
		return VOS_ERR;
	}
	
	p = str;
	while(*p != '\0')
	{
		hashNum[*p]++;
		p++;
	}

	p = str;
	while(*p!= '\0')
	{
		if (hashNum[*p] == 1)
		{
			*result = *p;
			return VOS_OK;
		}
		p++;
	}
	return VOS_ERR;

}

int main()
{
	char iChar;
	if (VOS_OK == GetFirstChar("aabcddb", &iChar))
	{
		printf("%c\n",iChar);
	}
	else
	{
		printf("Error!"); 
	} 	
}


面试题36数组中的逆序对

实现如下:

/* 求数组中的逆序对 */
#include <iostream>
#define VOS_OK  0
#define VOS_ERR 1
int Merge(int *numA, int begin,int mid, int end)
{
	int startA = begin;
	int startB = mid + 1;
	int *numB = (int *)malloc(sizeof(int)*(end + 1));
	int currentIndex = 0;
	long long result = 0;

	if (numA == NULL || begin > mid || mid > end)/* 其余异常函数调用处保证 */
	{
		return 0;
	}

	while (startA <=mid && startB <= end)
	{
		if (numA[startA] <= numA[startB])
		{
			numB[currentIndex] = numA[startA++];
		}
		else
		{
			numB[currentIndex] = numA[startB++];
			/* 前面的大于后面的,则前数组之后的元素也大于该元素 */
			result += mid - startA + 1;
		}


		currentIndex++;
	}

	while (startA <= mid)
	{
		numB[currentIndex++] = numA[startA++];
	}

	while (startB <= end)
	{
		numB[currentIndex++] = numA[startB++];
	}

    for (int i = begin; i <= end; i++)
    {
    	numA[i] = numB[i];
    }
    free(numB);

    return result;
	
}

int MergeSort(int *num, int start, int end)
{
	int result = 0;
	int mid;
	if (num == NULL || start >= end) /* 注意start == end 的时候*/
	{
		return 0;		
	}
	
	mid = (start + end)>>1;
	result = MergeSort(num, start, mid) + MergeSort(num, mid +1, end);
	result += Merge(num,start,mid,end);

	return result;

}

int main()
{
	int num[]={2,1,3,5,6};

	printf("%d\n",MergeSort(num, 0, 4));	
}


面试题37两个链表的第一个公共结点 

实现如下:

  1)暴力法

         每次遍历链表A,然后将链表A中当前结点在链表B中查找,如果找到则停止查找,返回。

  2)空间换取时间

       将两个链表都入栈,然后从最后一个结点开始比较,直到不相等为止。
  3)同时向后查找

   先遍历链表A得长度lengthA,再遍历链表B得长度lengthB

   假如A比B长n,则A先走n步,假如B比A长n,则B先走n步。

   然后同时向后走,直到第一个相等的结点


面试题38数字在排序数组中出现的次数 

有两种思路:利用二分查找法,找到该数中间出现的位置,然后分别向前后遍历相同数,可得到该数出现的次数

     利用二分查找法,找打该数最左边及最右边出现的位置,然后就可以求得该数出现的次数

左右查询实现如下:

#include <iostream>
int MaxSum(int num[], int length, int value)
{
	int iResult = 0;
	int i = 0;
	int j = length - 1;
	int mid;
	int k;

	while(i <= j )
	{
		mid = (i + j)>>1;
		if (num[mid] > value)
		{
			j= mid - 1;
		}
		else if (num[mid] < value)
		{
			i = mid + 1;
		}
		else
		{
			/* 向左查询*/
			k = mid-1;
			while (k >= i &&(num[k] == value))
			{
				k--;
				iResult++;
			}
			/* 向右查询*/
			k = mid+1;
			while (k <= j &&(num[k] == value))
			{	
				k++;
				iResult++;
			}
			printf("================");
			return iResult + 1;
		}
	}

	return iResult;
}

int main()
{
	int num[]={2,2,2,2,5,5,6,6};

	printf("%d\n",MaxSum(num, 8, 2) );
	getchar();
}

另外一种实现方法:

#include <iostream>
int GetFirstK(int num[], int length, int value)
{
	int mid;
	int i = 0;
	int j = length - 1;
	
	if (num == NULL)
	{
		return 0;
	}

	while (i <= j)
	{
		mid = (i + j)>>1;

		if (num[mid] > value)
		{
			j = mid - 1;
		}
		else if (num[mid] < value)
		{
			i = mid + 1;
		}
		else
		{
			if (mid -1 >= 0 && (num[mid - 1] == value))
			{
				j = mid - 1;
			}
			else
			{
				return mid;
			}
		}
	}

	return 0;
}

int GetLastK(int num[], int length, int value)
{
	int mid;
	int i = 0;
	int j = length - 1;
	
	if (num == NULL)
	{
		return 0;
	}

	while (i <= j)
	{
		mid = (i + j)>>1;

		if (num[mid] > value)
		{
			j = mid - 1;
		}
		else if (num[mid] < value)
		{
			i = mid + 1;
		}
		else
		{
			if (mid + 1 <= j && (num[mid + 1] == value))
			{
				i = mid + 1;
			}
			else
			{
				return mid;
			}
		}
	}

	return 0;
}

int main()
{
	int num[]={2,2,2,2,5,5,6,6};

	printf("%d\n",GetLastK(num, 8, 2) - GetFirstK(num, 8, 2) + 1);
	getchar();
}

面试题39二叉树的深度 

实现如下:

int DepthTree(BinaryNode *root)
{
	int leftDepth = 0;
	int rightDepth = 0;
	
	if (root == NULL)
	{
		return 0;
	}

	leftDepth = DepthTree(root->lchild);
	rightDepth = DepthTree(root->rchild);

	retrun (leftDepth > rightDepth)? (leftDepth + 1):(rightDepth + 1);	
}

扩展题目:判断一个树是否是平衡二叉树

实现如下:

bool IsBlanceTree(BinaryNode *root, int *depth)
{
	int leftDepth = 0;
	int rightDepth = 0;
	int diff;
	
	if (root == NULL)
	{
		return true;
	}

	leftDepth = DepthTree(root->lchild);
	rightDepth = DepthTree(root->rchild);

	if (IsBlanceTree(root->lchild, &leftDepth)
		&&IsBlanceTree(root->rchild, &rightDepth))
	{
		diff = leftDepth - rightDepth;
		if (diff < 1 && diff > -1)
		{
			*depth = (leftDepth > rightDepth)? (leftDepth + 1):(rightDepth + 1);
			return true;
		}
	}
	
	retrun false;	
}

面试题40数组中只出现一次的数字 :给一个数组,数组中有两个数只出现一次,其余数出现两次,求这两个数

思路:将数组分成两组,分别异或去重。如何分组呢?分组根据异或之后,最后一位二进制值为1的位分组。对数组一进行异或最后得一个数,对数组二异或,最后得另一个数。则最后得到的两个数是所求的数。

实现如下:

int FindFirstBitIsOne(int resultOR)
{
	for (int i = 0; i < 32; i++)
	{
		if (resultOR & (1 << i))
		{
			return i;
		}
	}
	return 0;
		
}

int IsBitOne(int data, int indexOfOne)
{
	return data & (1<<indexOfOne);

}
void FindNumsAppearOnce(int data[],int length,int *num1,int num2)
{
	if (data == NULL || length < 2)
	{
		return;
	}
	int resultOR = 0;
	for (int i = 0; i < length; i++)
	{
		resultOR ^=data[i];
	}
    
	int indexOfOne = FindFirstBitIsOne(resultOR);
	
	for (int j = 0; j < length; j++)
	{
			if (IsBitOne(data[j], indexOfOne))
			{
					*num1 ^=data[j];
			}
			else
			{
					*num2^=data[j];
			}
	}

}





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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值