(C/C++) 算法,编程题

注: 如下的题目皆来自互联网,答案是结合了自己的习惯稍作了修改。

1. 求一个数的二进制中的1的个数。

int func(int x)
{
    int count = 0; 

    while (x)
    {
        count++; 
        x = x& (x - 1); 
    }

    return count; 
}

2. 已知strcpy的函数原型:char *strcpy(char *strDest, const char *strSrc)其中strDest 是目的字符串,strSrc 是源字符串。不调用C++/C 的字符串库函数,请编写函数 strcpy。

int _tmain(int argc, _TCHAR* argv[])
{
    const char *srcStr = "This is a source string.";
    
    //char *desStr = (char *)malloc(sizeof(srcStr));    // Or below:
    char *desStr = (char *)malloc(sizeof(char)* strlen(srcStr) + 1); 

    myStrcpy(desStr, srcStr);

    printf("Copy result: %s", desStr); 
}

char *myStrcpy(char *strDest, const char *strSrc)
{
    if (strSrc == NULL || strDest == NULL)
    {
        return NULL; 
    }

    if (strDest == strSrc)
    {
        return strDest; 
    }

    char *strDestStart = strDest; 

    while (*strDest !='\0')
    {
        *strDest++ = *strSrc++;
    }

    return strDestStart;
}

3. 链表题:

一个链表的结点结构

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

  

(1)已知链表的头结点head,写一个函数把这个链表逆序

思路: 用三个指针p0,p1,p2,从头到尾依次遍历并反转结点

int _tmain(int argc, _TCHAR* argv[])
{
	int linkedListLength = 5; 
	Node *myList = new Node(); 
	Node *p = myList; 
	printf("Original linked list is:"); 
	for (int i = 0; i < linkedListLength; i++)
	{
		Node *node = new Node(); 
		node->data = i;
		printf(" %d", i);
		p->next = node;
		p = node;
	}

	Node *reversedMyList = ReverseLinkedList(myList); 

	printf("\r\nReversed linked list is:"); 
	Node *r = reversedMyList; 
	while (r->next != NULL)
	{
		printf(" %d", r->data); 
		r = r->next;
	}
}

Node *ReverseLinkedList(Node *head)
{
	// NULL
	if (head == NULL)
	{
		return NULL; 
	}

	// One node only.
	if (head->next == NULL)
	{
		return head; 
	}

	// Two or more than two nodes.
	Node *p0 = head; 
	Node *p1 = p0->next; 
	Node *p2 = p1->next;   //p2 maybe null; 

	p0->next = NULL;

	while (p2 != NULL)
	{
		p1->next = p0; 
		p0 = p1;
		p1 = p2;
		p2 = p2->next; 
	}
		
	p1->next = p0; 
	return p1; 
}

(2)已知两个链表head1 和head2 各自有序,请把它们合并成一个链表依然有序。(保留所有结点,即便大小相同)

思路: 从head1 和 head2 中找一个较小值定义为head,然后一次用p0,p1遍历两个链表,逐步的插入到新链表里(currnt)。

int _tmain(int argc, _TCHAR* argv[])
{
	Node *p0 = new Node(); 
	Node *p1 = new Node(); 
	int data0[5] = { 1, 3, 5, 8, 10}; 
	int data1[3] = { 2, 6, 7 }; 

	Node *head0 = p0; 
	Node *head1 = p1; 
	for (int i = 0; i < sizeof(data0)/sizeof(data0[0]); i++)
	{
		Node *tmp0 = new Node();
		tmp0->data = data0[i]; 
		p0->next = tmp0; 
		p0 = p0->next; 
	}

	for (int j = 0; j < sizeof(data1)/sizeof(data1[0]); j++)
	{
		Node *tmp1 = new Node();
		tmp1->data = data1[j];
		p1->next = tmp1;
		p1 = p1->next; 
	}

	head0 = head0->next;
	head1 = head1->next; 
	Node *mergedList = MergeSortedLinkedList(head0, head1); 
}


Node *MergeSortedLinkedList(Node *head0, Node *head1)
{
	if (head0 == NULL)
	{
		return head1; 
	}

	if (head1 == NULL)
	{
		return head0; 
	}

	// Set new head for new merged sorted list.
	Node *head = NULL; 
	Node *p0 = head0; 
	Node *p1 = head1;
	if (head0->data < head1->data)
	{
		head = head0;
		p0 = p0->next;
	}
	else
	{
		head = head1;
		p1 = p1->next; 
	}

	Node *current = head; 
	while (p0 != NULL && p1 != NULL)
	{
		// Insert the value which is smaller.
		if (p0->data < p1->data)
		{
			current->next = p0; 
			current = p0; 
			p0 = p0->next;
		}
		else
		{
			current->next = p1; 
			current = p1; 
			p1 = p1->next; 
		}

	}

	// All of nodes of one list have been added into new merged list. so add the rest nodes of the other list.
	if (p0 == NULL)
	{
		current->next = p1; 
	}

	if (p1 == NULL)
	{
		current->next = p0; 
	}

	return head; 
}

另外可以也可以采用递归(recursive)算法:

顺便补充一下递归算法的特点,其关键就是定义一个递归公式和递归结束条件。

(1) 递归就是在过程或函数里调用自身。
(2) 在使用递归策略时,必须有一个明确的递归结束条件,称为递归出口。
(3) 递归算法解题通常显得很简洁,但递归算法解题的运行效率较低。所以一般不提倡用递归算法设计程序。
(4) 在 递归调用的过程当中系统为每一层的返回点、局部量等开辟了栈来存储。递归次数过多容易造成 栈溢出等。所以一般不提倡用递归算法设计程序。
 
Node * MergeRecursive(Node *head0, Node *head1)
{
	if (head0 == NULL)
	{
		return head1;
	}

	if (head1 == NULL)
	{
		return head0;
	}

	Node *head = NULL;
	if (head0->data < head1->data)
	{
		head = head0;
		head->next = MergeRecursive(head0->next, head1);
	}
	else
	{
		head = head1;
		head->next = MergeRecursive(head0, head1->next);
	}

	return head;
}

  (3)Implement an Algorithm to check if the link list is in Ascending order?

思路: 遍历链表,只要找到某个结点的值比下个结点的值大,那么就可以判断为false。

bool IsAscendingList(Node *head)
{
	Node *p = head; 
	while (p->next != NULL)
	{
		if (p->data > p->next->data)
		{
			return false; 
		}

		p = p->next; 
	}
	return true; 
}

  

 4.   写一个函数找出一个整数数组中,第二大的数
思路:一次遍历数组找出最大和次大数。
int _tmain(int argc, _TCHAR* argv[])
{
	int data0[5] = { 1, 3, 9, 8, 10}; 
	//int data1[7] = { 9, 1, 2, 4, 6, 10}; 
	int data1[7] = { 9, 4, 7, 6, 6};
	
	int secMax0 = FindSecondMax(data0, sizeof(data0) / sizeof(data0[0])); 
	int secMax1 = FindSecondMax(data1, sizeof(data1) / sizeof(data1[0]));
}

int FindSecondMax(int *data, int dataLength)
{
	if (dataLength <= 1)
	{
		printf("The length of data should be more than 1."); 
		return -1; 
	}

	int max = data[0]; 
	int secondMax = MIN_INT;

	for (int i = 1; i < dataLength; i++)
	{
		if (data[i] > max)
		{
			secondMax = max;
			max = data[i];
		}
		else
		{
			if (data[i] > secondMax)
			{
				secondMax = data[i]; 
			}
		}
	}

	return secondMax; 
}

5. 将数a、b的值进行交换,并且不使用任何中间变量.

思路: 采用异或运算(三次异或后,就被交换), 或加减运算。

int _tmain(int argc, _TCHAR* argv[])
{
	int a = 18; 
	int b = 32; 

	// Swap withouth other variables.  3 times XOR will swap two values. (1^1 = 0, 0^0 =0, 1^0 =1, 0^1 =1). 
	a ^= b; 
	b ^= a; 
	a ^= b; 

	printf("a:%d, b:%d", a, b); 

	// method2
	a = a + b; 
	b = a - b; 
	a = a - b; 

	printf("a:%d, b:%d", a, b); 

}

6. 题目:在一个字符串中找到第一个只出现一次的字符。如输入abaccdeff,则输出b。

分析:这道题是2006 年google 的一道笔试题。

思路:采用bitmap或者byteArray的思路,遍历字符串,每个字符对应的整数值为index。 Array里保存字符出现的次数。

// Assuming the char is ASCII
char FirstSingleChar(char *str)
{
	int bitmap[255]; 
	memset(bitmap, 0, 255 * sizeof(int)); 

	char *p = str;

	while (*p != '\0')
	{
		bitmap[*p]++; 
		p++; 
	}

	p = str;	
	while (*p!='\0')
	{
		if (bitmap[*p] == 1)
		{
			return *p; 
		}
	}

	return '\0'; 
}

7.题目:输入一个表示整数的字符串,把该字符串转换成整数并输出。
例如输入字符串"345",则输出整数345。

思路: 遍历字符串,逐字符转换为整数(和‘0'做差), 其中注意一下对负数和数字的判断。

int ConvertStrToInt(char *str)
{
	char *p = str; 
	int result = 0; 
	int asciiToInt = 0; 
	bool isPostive = true; 

	if (*p == '-')
	{
		isPostive = false;
		p++; 
	}
	else if (*p == '+')
	{
		p++; 
	}

	while (*p != '\0')
	{
		if (IsNumber(*p))
		{
			asciiToInt = *p - '0';
			result = result * 10 + asciiToInt;
			p++;
		}
		else
		{
			//Had better throw exception here.
			printf("Illegal number: %c", *p); 
			break; 
		}
	}

	if (!isPostive)
	{
		result = 0 - result; 
	}

	return result; 
}

8.  Reverse a string. 

思路: 用两个指针指向一头一尾。然后向中间遍历,并逐个字符交换。

int _tmain(int argc, _TCHAR* argv[])
{
	// char *strForTest = "+345abc" will cause "access violation writing location". http://stackoverflow.com/questions/14664510/access-violation-writing-location
	char strForTest[] = "I like money"; 
	ReverseWordsInSentence(strForTest); 
}


void ReverseString(char *str)
{
	int strLength = strlen(str); 
	ReverseStringInFixedLength(str, strLength); 
}

void ReverseStringInFixedLength(char *str, int strLength)
{
	char *p1 = str;
	char *p2 = str + strLength -1;
	char tmp;
	while (p1 < p2)
	{
		// Swap two chars. 
		tmp = *p1;
		*p1 = *p2;
		*p2 = tmp;

		p1++;
		p2--;
	}
}

  

9. Revese words in a sentense. for example. reverse "I like money" to "money like I". 

思路:Reverse the whole string, then reverse each word. Using the reverseStringInFixedLength() above.

void ReverseWordsInSentence(char *sen)
{
	ReverseString(sen); 

	char *pStartOfWord = sen; 
	char *p = pStartOfWord; 

	while (*p != '\0')
	{
		// Skip blank spaces. 
		while (*p == ' ' && *p != '\0')
		{
			p++; 
		}

		pStartOfWord = p; 

		while (*p != ' ' && *p != '\0')
		{
			p++; 
		}
		
		int wordLength = p - pStartOfWord; 

		ReverseStringInFixedLength(pStartOfWord, wordLength);
	}
}

10.  给出一个数组,还有一个给定的数,打印出数组中的一对数(不重复),使其和等于指定的数

思路:先排序(快排),然后再用两个指针从头尾依次向中间遍历。如果和大于期待的值,那么左移right指针,如果小于期待的值,那么右移left指针。

For sorted array,  the time complexity is O(n).   
For unsorted array, we may do a quick sort and then call our method.  The time complexity is O(nlogn).

Here is the C++ sample codes, and I have checked it works well. 

int _tmain(int argc, _TCHAR* argv[])
{
       int nums[7] = { 1, 2, 3, 3, 4, 4, 5 }; 

       printUniquePairs(nums, 7, 7); 

}

void printUniquePairs(int *numbers, int numbersLength, int expectedSum)
{
       int sum = 0; 

       //Augrments judgements. e.g. Null, length. 
       if (numbersLength < 2)
       {
              printf("Number length should be more than 2.");
              return; 
       }

       // Quick sort. 
       QuickSort(numbers); 

       // Use two points (left, and right) moving from two sides into the center.
       int *p1 = numbers; 
       int *p2 = numbers + numbersLength - 1; 
       int previousP1Value; 
       int previousP2Value; 

       while (p1 < p2)
       {
              sum = *p1 + *p2; 
              previousP1Value = *p1;
              previousP2Value = *p2;

              if (sum == expectedSum)
              {
                     printf("Print unique pair: %d, %d.", *p1, *p2);

                     p1++; 
                     p2--; 

                     // If the value is duplicated, then skip. 
                     if (previousP1Value == *p1)
                     {
                           p1++;
                     }

                     if (previousP2Value == *p2)
                     {
                           p2--;
                     }

              }
              else if (sum < expectedSum)
              {
                     p1++; 

                     // If the value is duplicated, then skip. 
                     if (previousP1Value == *p1)
                     {
                           p1++; 
                     }
              }
              else if (sum > expectedSum)
              {
                     p2--; 

                     if (previousP2Value == *p2)
                     {
                           p2--; 
                     }
              }
       }

  

转载于:https://www.cnblogs.com/fdyang/p/4387663.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值