剑指offer(C语言)60-68

61 扑克牌中的顺子

题目:从扑克牌中随机抽5张牌,判断是不是一个顺子,即这5张牌是不是连续的。2-10为数字本身,A为1,J为11,Q为12,K为13,而大小王可以看成任意数字。
思路:抛开扑克牌,就是五个1-13的数字,判断是否连续。可以把大小王看成0.先把数字排序,可以采用C语言库中的快排。之后遍历数组,分别统计0的个数,和间距的大小。最后判断0个个数是不是比间距小就行了。当数组中两个数相等的时候可以直接返回失败。
注意:使用快排的时候还需要传汝一个函数指针,用来判定是从小到大排序还是从大到小排序。

#include 
#include 
#include 
#define bool unsigned int
#define true 1
#define false -1
#define none 2

int compare(const void* arg1,const void* arg2)
{
	return *(int*)arg1-*(int*)arg2;//从小到大排序
	//return *(int*)arg2-*(int*)arg1;//从大到小排序
}
bool IsContinuous(int* numbers,int length)
{
	int i = 0;
	int numberOf0 = 0;
	int numberOfUncontinuous = 0;

	if(numbers==NULL || length<1)return false;
	qsort(numbers,length,sizeof(int),compare);

	for(i=0;i<length;i++)
	{
		if(numbers[i]==0)numberOf0++;
		else if(i>0)
		{
			if(numbers[i-1]!=0 && numbers[i]==numbers[i-1])
				return false;
			if(numbers[i-1]!=0 && numbers[i]-numbers[i-1]!=1)
				numberOfUncontinuous+=(numbers[i]-numbers[i-1]-1);
		}
	}
	if(numberOf0<numberOfUncontinuous)
		return false;
	else 
		return true;
	
}
void main()
{
	int numbers[] = {0,0,3,3,6};
	int i;
	bool status;
	status = IsContinuous(numbers,sizeof(numbers)/sizeof(int));
	printf("%d",status);
	
}

62 圆圈中最后剩下的数字

题目:0,1,…,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字。求出这个圆圈里剩下的最后一个数字。
思路:建立一个环形链表,建立一个指针指向头,每次循环m-1次,删除该指针指向的节点,然后再把链表接起来。最后当链表中只剩一个的时候把该节点的数值返回。

#include 
#include 
#include 
#define bool unsigned int
#define true 1
#define false -1
#define none 2

typedef struct ListNode
{
	int data;
	struct ListNode* next;
}ListNode;

void ConnectListNodes(ListNode* node1,ListNode* node2)
{
	node1->next = node2;
}

ListNode* CreateListNode(int data)
{
	ListNode* newListNode = (ListNode*)malloc(sizeof(ListNode));
	if(!newListNode)return NULL;
	newListNode->data = data;
	newListNode->next = NULL;
	return newListNode;
}

int LastRemaining(unsigned int n,unsigned int m)
{
	int i=0;
	int data = 0;
	ListNode* p = NULL;
	ListNode* preNode = NULL;
	ListNode** node = (ListNode**)malloc(sizeof(ListNode*)*n);
	if(n<1 || m<1)return false;
	for(i=0;i<n;i++)
	{
		node[i] = CreateListNode(i);
		if(i>0)
			ConnectListNodes(node[i-1],node[i]);
	}
	ConnectListNodes(node[n-1],node[0]);

	p=node[0];
	preNode = node[0];
	while(p->next != p)
	{
		for(i=0;i<m-1;i++)
		{
			p = p->next;
		}
		while(preNode->next!=p)
			preNode = preNode->next;
		if(preNode!=p)
		{
			preNode->next = p->next;
			free(p);
			p = preNode->next;
		}
	}
	data = p->data;
	free(p);
	free(node);
	return data;
}

void main()
{
	int data =LastRemaining(4000,997);//1027
	printf("%d",data);
}

63 股票的最大利润

题目:假设把某股票的价格按照时间先后顺序存储在数组中,请问买卖该股票一次可能获得的最大利润是多少?例如,一只股票某些时间节点的价格为{9,11,8,5,7,12,16,14}。如果我们能在价格为5的时候买入并在价格为16时卖出,则能收获的最大利润为11.
思路:因为是买卖一次,所以就是选一个最小的,然后在他后面选一个最大的卖出去。可以使用蛮力法,求出每个值与他后面的值的差值,时间复杂度为O(N2)。之后找出所有差值中的最大值
优化:可以使用动态规划的想法,从第二个数开始,假设在该数卖出,在前面最小的时候买入。每次更新最小值就可以了。

#include 
#include 
#include 
#define bool unsigned int
#define true 1
#define false -1
#define none 2

int MaxDiff(int* numbers,unsigned int length)
{
	int minCost;
	int maxDiff;
	int i;
	if(numbers==NULL ||length<2)return 0;
	minCost = numbers[0];
	maxDiff = numbers[1]- numbers[0];
	for(i=2;i<length;i++)
	{
		if(numbers[i-1]<minCost)
			minCost = numbers[i-1];
		if(numbers[i]-minCost>maxDiff)
			maxDiff = numbers[i]-minCost;
	}
	return maxDiff;
}

void main()
{
	int numbers[] = {9,11,8,5,7,12,16,14};
	int maxDiff;
	maxDiff = MaxDiff(numbers,sizeof(numbers)/sizeof(int));
	printf("%d",maxDiff);

}

64 求1+2+…+n

题目:求1+2+…+n,要求不能使用乘除法,for,while,if,else,switch,case等关键字以及条件判断语句(A?B:C)
思路:不能用乘法不能用循环,那就只能用递归了,递归有一个问题就是最后返回时必须需要判断一下是不是到0了。不能通过判断来停止递归,那可以写两个函数,其中一个函数是正常的递归函数,另外一个是返回的函数,然后用函数指针指向这两个函数。当n等于0时调用返回的函数。通过函数指针数组来决定调用哪个函数,只有0和1两个选择,把N进行两次取反就可以了return n+f!!n;当n>0时两次取反得到1,当n=0时就是0

#include 
#include 
#include 
#define bool unsigned int
#define true 1
#define false -1
#define none 2

typedef unsigned int (*fun)(unsigned int);

unsigned int Solution_Teminator(unsigned int n)
{
	return 0;
}

unsigned int Solution(unsigned int n)
{
	fun f[2] = {Solution_Teminator,Solution};
	return n+f[!!n](n-1);
}

void main()
{
	int data = Solution(5);
	printf("%d",data);
}

65 不用加减乘除做加法

题目:写一个函数,求两个整数之和,要求在函数体内不得使用加减乘除四则运算符号
思路:加法的过程主要分两步,第一步是不进位的把两个数按位相加,第二步是把进位加上去。在二进制里面,按位相加其实就是异或,都是0都是1最后都是0.进位的数其实就是两个数做与运算然后左移一位,只有都是1的时候才会是1.然后把这两个数在做同样的运算,知道没有进位的数。

#include 
#include 
#include 
#define bool unsigned int
#define true 1
#define false -1
#define none 2

int Add(int num1,int num2)
{
	int sum;
	int carry;
	while(num2)
	{
		sum = num1^num2;
		carry = (num1 & num2)<<1;
		num1 = sum;
		num2 = carry;
	}
	return num1;
}

void main()
{
	int data = Add(5,6);
	printf("%d",data);
}

66 构建乘积数组(暂过)

题目:给定一个数组A[0,1,…,n-1],请构建一个数组B[0,1,…,n-1],其中B中的元素B[i]=A[0]×A[1]×…×A[i-1]×A[i+1]×…×A[n-1].不能使用乘除法。

67 把字符串转换成整数

题目:写一个函数,实现把字符串转换成整数这个功能。
思路:不考虑任何边界条件,那就不断乘10加本身就好了

#include 
#include 
#include 
#define bool unsigned int
#define true 1
#define false -1
#define none 2

int StringToInt(char* str)
{
	int result = 0;
	if(str==NULL)return false;
	while(*str!='\0')
	{
		result = *str++ -'0'+result*10;
		//str++;
	}
	return result;
}

void main()
{
	char* str = "123";
	int a = StringToInt(str);
	printf("%d",a);
}

优化:实际上在输入字符串的过程中,会有很多非法输入,要对这些非法输入进行很好的判断。并且当错误输入时用一个标志位来标志一下。
1.输入NULL或者‘\0’
2.输入符号±
3.输入字符比0x7fff ffff还大或者比0x80000000还小
4.输入不在‘0’到‘9’范围内的数

#include 
#define bool unsigned int
#define true 1
#define false -1
#define none 2
enum Status{kValid=0,kInvalid};
int states = kInvalid;

long long StrToIntCore(char* digit,int minus)
{
	long long num = 0;
	int flag = minus?-1:1;
	while(*digit!='\0')
	{
		if(*digit>='0'&&*digit<='9')
		{
			num = num*10 + flag*(*digit-'0');
			if((!minus && num>0x7fffffff) || (minus && num<(signed int)0x80000000))
			{
				num = 0;
				break;
			}
		}
		else
		{
			num = 0;
			break;
		}
		digit++;
	}
	if(*digit == '\0')
		states = kValid;
	return num;
}

int StrToInt(char* str)
{
	long long num = 0;
	int minus = 0;
	if(str == NULL || *str == '\0')return 0;

	if(*str == '+')str++;
	else if(*str == '-')
	{
		str++;
		minus = 1;
	}
	num = StrToIntCore(str,minus);
	return (int)num;
}

void main()
{
	char str[] = "-123";
	//int data = atoi("132");
	int data = StrToInt(str);
	printf("%d",data);
}

68 树中两个节点的最低公共祖先

你可能感兴趣的:(剑指offer(C语言)60-68)