算法题主要来自剑指offer上面的题目,本章主要是重新复习下线性表及其相关的算法题。
二维数组中的查找
在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
class Solution {
public:
bool Find(vector<vector<int> > array,int target) {
bool isFind = false;
if (array.size() == 0) {
return isFind;
}
int currentRow = 0;
int currentColumn = array[0].size() - 1;
while (currentRow <= array.size()-1 && currentColumn >= 0) {
vector<int> rowVector = array[currentRow];
if (rowVector[currentColumn] > target) {
currentColumn--;
}else if (rowVector[currentColumn] < target){
currentRow++;
}else{
// 相等,说明找到
isFind = true;
return isFind;
}
}
return isFind;
}
};
从尾到头打印链表
输入一个链表,从尾到头打印链表每个节点的值。
输入描述
输入为链表的表头
输出描述
输出为需要打印的“新链表”的表头
/** * struct ListNode { * int val; * struct ListNode *next; * ListNode(int x) : * val(x), next(NULL) { * } * }; */
class Solution {
public:
vector<int> printListFromTailToHead(struct ListNode* head) {
stack<int> stack;
vector<int> result;
ListNode *pNode = head;
if (pNode == NULL) {
return result;
}
while (pNode!= NULL) {
stack.push(pNode->val);
pNode = pNode->next;
}
while (!stack.empty()) {
result.push_back(stack.top());
stack.pop();
}
return result;
}
};
链表中环的入口结点
一个链表包含环,请找出该链表的环的入口结点
/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) { } }; */
class Solution {
public:
/** * 找出两个快慢结点相遇的结点 * * @param pHead <#pHead description#> * * @return <#return value description#> */
ListNode* meetNode(ListNode* pHead){
// 慢结点,每次移动1步
ListNode *pSlowNode = pHead;
// 快结点,每次移动2步
ListNode *pFastNode = pHead->next;
if (pHead == NULL) {
return NULL;
}
if (pHead->next == NULL) {
return NULL;
}
while (pSlowNode != pFastNode) {
pSlowNode = pSlowNode->next;
pFastNode = pFastNode->next->next;
}
return pSlowNode;
}
/** * 求出头结点到相遇结点的距离 * * @param pHead <#pHead description#> * @param pMeetNode <#pMeetNode description#> * * @return <#return value description#> */
int distanceFormHeadToMeetNode(ListNode* pHead,ListNode* pMeetNode)
{
int distance = 0;
ListNode* pNode = pHead;
while (pNode != pMeetNode) {
distance++;
pNode = pNode->next;
}
return distance;
}
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
if (pHead == NULL) {
return NULL;
}
if (pHead->next == NULL) {
return NULL;
}
ListNode* pNode1 = pHead;
ListNode* pNode2 = pHead->next;
ListNode* pMeetNode = meetNode(pHead);
int distance = distanceFormHeadToMeetNode(pHead, pMeetNode);
// pHead2先移动distance个距离
while (distance != 0) {
pNode2 = pNode2->next;
distance--;
}
while (pNode1 != pNode2) {
pNode1 = pNode1->next;
pNode2 = pNode2->next;
}
return pNode1;
}
};
反转链表
输入一个链表,反转链表后,输出链表的所有元素。
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* ReverseList(ListNode* pHead) {
ListNode* pReversedHead = NULL;
ListNode* pNode = pHead;
ListNode* pPrev = NULL;
while (pNode != NULL) {
ListNode* pNext = pNode->next;
if (pNext == NULL) {
pReversedHead = pNode;
}
pNode->next = pPrev;
pPrev = pNode;
pNode = pNext;
}
return pReversedHead;
}
};
链表中倒数第k个结点
输入一个链表,输出该链表中倒数第k个结点。
需要遍历两次的算法
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
// 先求出链表长度length,倒数第k个结点相当于第 length - k + 1个结点
ListNode* pNode = pListHead;
if (pListHead == NULL) {
return NULL;
}
int length = 1;
while (pNode != NULL) {
length++;
pNode = pNode->next;
}
pNode = pListHead;
ListNode *pFindNode = NULL;
// 取得了链表的长度length后,找到第 length - k + 1
int count = 1;
while (pNode != NULL) {
count++;
if (count == length - k + 1) {
pFindNode = pNode;
break;
}
pNode = pNode->next;
}
return pFindNode;
}
};
只需遍历一次的算法(使用两个指针)(注意代码的鲁棒性)
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
if (pListHead == NULL || k== 0) {
return NULL;
}
ListNode* pAheadNode = pListHead;
ListNode* pBehind = pListHead;
for (int i = 0; i < k-1; i++) {
// pAheadNode向前移动
if (pAheadNode->next != NULL) {
pAheadNode = pAheadNode->next;
}else{
return NULL;
}
}
while (pAheadNode->next != NULL) {
pBehind = pBehind->next;
pAheadNode = pAheadNode->next;
}
return pBehind;
}
};
合并两个排序的链表(注意采用递归的思想)
输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
不用递归的思想
/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) { } };*/
class Solution {
public:
ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
{
ListNode* pHead = NULL;
ListNode* pLast = NULL;
if (pHead1 == NULL && pHead2 == NULL) {
return NULL;
}else if (pHead1 == NULL && pHead2 != NULL){
return pHead2;
}else if (pHead1 != NULL && pHead2 == NULL){
return pHead1;
}else{
ListNode* pNode1 = pHead1;
ListNode* pNode2 = pHead2;
// 先找出链表的头结点
if (pNode1->val <= pNode2->val) {
pHead = pNode1;
pNode1 = pNode1->next;
}else{
pHead = pNode2;
pNode2 = pNode2->next;
}
pLast = pHead;
while (pNode1 != NULL || pNode2 != NULL) {
ListNode* pNode = NULL;
if (pNode1 == NULL) {
pLast->next = pNode2;
return pHead;
}
if (pNode2 == NULL) {
pLast->next = pNode1;
return pHead;
}
if (pNode1->val <= pNode2->val) {
pNode = pNode1;
pNode1 = pNode1->next;
}else{
pNode = pNode2;
pNode2 = pNode2->next;
}
// 找到最小的结点后,最后一个结点指向该结点
pLast->next = pNode;
pLast = pNode;
}
}
return pHead;
}
};
使用递归的思想
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
{
if (pHead1 == NULL) {
return pHead2;
}
if (pHead2 == NULL) {
return pHead1;
}
ListNode* pHead = NULL;
if (pHead1->val < pHead2->val) {
pHead = pHead1;
pHead->next = Merge(pHead1->next, pHead2);
}else{
pHead = pHead2;
pHead->next = Merge(pHead1, pHead2->next);
}
return pHead;
}
};
复杂链表的复制
输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)
/*
struct RandomListNode {
int label;
struct RandomListNode *next, *random;
RandomListNode(int x) :
label(x), next(NULL), random(NULL) {
}
};
*/
class Solution {
public:
RandomListNode* Clone(RandomListNode* pHead)
{
if(!pHead) return NULL;
RandomListNode *currNode = pHead;
while(currNode){
RandomListNode *node = new RandomListNode(currNode->label);
node->next = currNode->next;
currNode->next = node;
currNode = node->next;
}
currNode = pHead;
while(currNode){
RandomListNode *node = currNode->next;
if(currNode->random){
node->random = currNode->random->next;
}
currNode = node->next;
}
//拆分
RandomListNode *pCloneHead = pHead->next;
RandomListNode *tmp;
currNode = pHead;
while(currNode->next){
tmp = currNode->next;
currNode->next =tmp->next;
currNode = tmp;
}
return pCloneHead;
}
};
两个链表的第一个公共结点
输入两个链表,找出它们的第一个公共结点。
/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) { } };*/
class Solution {
public:
ListNode* FindFirstCommonNode( ListNode *pHead1, ListNode *pHead2) {
if (pHead1 == NULL || pHead2 == NULL) {
return NULL;
}
// 分别计算两个链表的长度
int length1 = 1;
int length2 = 1;
ListNode* pNode1 = pHead1;
ListNode* pNode2 = pHead2;
while (pNode1->next != NULL) {
length1++;
pNode1 = pNode1->next;
}
while (pNode2->next != NULL) {
length2++;
pNode2 = pNode2->next;
}
// 比较两个链表的长度
int distance = length1 - length2;
if (distance > 0) {
// 说明链表1的长度长,链表1先走distance步。
while (distance > 0) {
pHead1 = pHead1->next;
distance--;
}
}else{
// 链表2的长度长
distance = -distance;
while (distance > 0) {
pHead2 = pHead2->next;
distance--;
}
}
ListNode* commonNode = NULL;
// 此时两个链表走的长度是相同的,可以同时遍历
while (pHead1 != pHead2 && pHead1 != NULL && pHead2 != NULL) {
pHead1 = pHead1->next;
pHead2 = pHead2->next;
}
commonNode = pHead1;
return commonNode;
}
};
删除链表中重复的结点
在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5
/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) { } }; */
// 递归
class Solution {
public:
ListNode* deleteDuplication(ListNode* pHead)
{
if (pHead==NULL)
return NULL;
if (pHead!=NULL && pHead->next==NULL)
return pHead;
ListNode* current;
if ( pHead->next->val==pHead->val){
current=pHead->next->next;
while (current != NULL && current->val==pHead->val)
current=current->next;
return deleteDuplication(current);
}
else {
current=pHead->next;
pHead->next=deleteDuplication(current);
return pHead;
}
}
};
旋转数组的最小数字
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。