数据结构常见编程题小结解析.docx
- 文档编号:11780265
- 上传时间:2023-04-01
- 格式:DOCX
- 页数:37
- 大小:222.49KB
数据结构常见编程题小结解析.docx
《数据结构常见编程题小结解析.docx》由会员分享,可在线阅读,更多相关《数据结构常见编程题小结解析.docx(37页珍藏版)》请在冰豆网上搜索。
数据结构常见编程题小结解析
1、单链表
因为单链表要考虑的可能性比较少,所以单链表的题目比较简单,而且比较常考。
特别要注意的是链表的数据的插入和删除,因为(没有头节点)的单链表在第一个元素之前插入和删除和最后一个元素的插入删除需要特别考虑。
做题时,最好把单链表的示意图画出来,这样就很方便写代码了。
常用技巧:
快慢指针,拆分链表
数据结构定义如下:
C++Code
1
2
3
4
5
struct ListNode {
int val;//值
ListNode *next;//下一个元素
ListNode(int x) :
val(x), next(NULL) {}//new初始化
};
下面是一些常考的题目:
(1)LinkedListCycle-判断一个链表是否有环
最好的方法是时间复杂度O(n),空间复杂度O
(1)的。
设置两个指针,一个快一个慢,快的指针每次走两步,慢的指针每次走一步,如果快指针和慢指针相遇,则说明有环。
(如何证明,上网找找)
代码实现如下:
C++Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//LeetCode, Linked List Cycle
// 时间复杂度 O(n),空间复杂度 O
(1)
class Solution
{
public:
bool hasCycle(ListNode *head)
{
// 设置两个指针,一个快一个慢
ListNode *slow = head, *fast = head;
while (fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
if (slow == fast) return true;
}
return false;
}
};
(2)LinkedListCycleII-链表有环,找出环的起始点
当fast与slow相遇时,slow肯定没有遍历完链表,而fast已经在环内循环了n圈(1n)。
假
设slow走了s步,则fast走了2s步(fast步数还等于s加上在环上多转的n圈),设环长为r,则:
2s=s+nr
s=nr
设整个链表长L,环入口点与相遇点距离为a,起点到环入口点的距离为x,则
x+a=nr=(n–1)r+r=(n1)r+Lx
x=(n1)r+(L–x–a)
L–x–a为相遇点到环入口点的距离,由此可知,从链表头到环入口点等于n1圈内环+相遇
点到环入口点,于是我们可以从head开始另设一个指针slow2,两个慢指针每次前进一步,它俩
一定会在环入口点相遇。
C++Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//LeetCode, Linked List Cycle II
// 时间复杂度 O(n),空间复杂度 O
(1)
class Solution
{
public:
ListNode *detectCycle(ListNode *head)
{
ListNode *slow = head, *fast = head;
while (fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
if (slow == fast)
{
ListNode *slow2 = head;
while (slow2 !
= slow)
{
slow2 = slow2->next;
slow = slow->next;
}
return slow2;
}
}
return nullptr;
}
};
(3)AddTwoNumber
Youaregiventwolinkedlistsrepresentingtwonon-negativenumbers.Thedigitsarestoredinreverse
orderandeachoftheirnodescontainasingledigit.Addthetwonumbersandreturnitasalinkedlist.
Input:
(2->4->3)+(5->6->4)
Output:
7->0->8
代码实现如下:
C++Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// LeetCode, Add Two Numbers
// 跟 Add Binary 很类似
// 时间复杂度 O(m+n),空间复杂度 O
(1)
class Solution
{
public:
ListNode *addTwoNumbers(ListNode *l1, ListNode *l2)
{
ListNode dummy(-1); // 头节点
int carry = 0;
ListNode *prev = &dummy;
for (ListNode *pa = l1, *pb = l2;
pa !
= nullptr || pb !
= nullptr;
pa = pa == nullptr ?
nullptr :
pa->next,
pb = pb == nullptr ?
nullptr :
pb->next,
prev = prev->next)
{
const int ai = pa == nullptr ?
0 :
pa->val;
const int bi = pb == nullptr ?
0 :
pb->val;
const int value = (ai + bi + carry) % 10;
carry = (ai + bi + carry) / 10;
prev->next = new ListNode(value); // 尾插法
}
if (carry > 0)
prev->next = new ListNode(carry);
return dummy.next;
}
};
(4)PartitionList
描述
Givenalinkedlistandavaluex,partitionitsuchthatallnodeslessthanxcomebeforenodesgreater
thanorequaltox.
Youshouldpreservetheoriginalrelativeorderofthenodesineachofthetwopartitions.
Forexample,Given1->4->3->2->5->2andx=3,return1->2->2->4->3->5.
C++Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// LeetCode, Partition List
// 时间复杂度 O(n),空间复杂度 O
(1)
class Solution
{
public:
ListNode *partition(ListNode *head, int x)
{
ListNode left_dummy(-1); // 头结点
ListNode right_dummy(-1); // 头结点
auto left_cur = &left_dummy;
auto right_cur = &right_dummy;
for (ListNode *cur = head; cur; cur = cur->next)
{
if (cur->val < x)
{
left_cur->next = cur;
left_cur = cur;
}
else
{
right_cur->next = cur;
right_cur = cur;
}
}
left_cur->next = right_dummy.next;
right_cur->next = nullptr;
return left_dummy.next;
}
};
2、栈和队列
基本概念:
手动实现一个栈或者队列。
剑指offer上面的最大栈的实现。
3、字符串
常用C语言库实现:
C++Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
char *strcpy(char *dst,const char *src){
if(dst==src) return dst;
assert(dst!
=NULL&&src!
=NULL);
char *addr=dst;
while((*dst++=*src++)!
='\0');
return addr;
}
int strcmp(const char *s,const char *t){
assert(s!
=NULL&&t!
=NULL)
while(*s&&*t&&*s==*t)
{
++s;
++t;
}
return (*s-*t);
}
void memcpy(void *dst,const void *src,int count){
assert(dst!
=NULL&&src!
=NULL);
void *addr=dst;
while(cout--){
*(char *)dst=*(char *)src;
dst=(char *)dst++;
src=(char *)src++;
}
return addr;
}
int memcmp(const void *s,const void *t,int count){
assert(s!
=NULL&&t!
=NULL);
while(*(char *)s&&*(char*)t&&*(char *)s=*(char *)t
&&count--){
s=(char *)s++;
t=(char *)t++;
}
return (*(char *)s-*(char *)t);
}
4、数组
(1)TwoSum
Givenanarrayofintegers,findtwonumberssuchthattheyadduptoaspecifictargetnumber.
ThefunctiontwoSumshouldreturnindicesofthetwonumberssuchthattheyadduptothetarget,where
index1mustbelessthanindex2.Pleasenotethatyourreturnedanswers(bothindex1andindex2)arenot
zero-based.
Youmayassumethateachinputwouldhaveexactlyonesolution.
Input:
numbers={2,7,11,15},target=9
Output:
true
分析:
先排序,然后左右夹逼,排序O(nlogn),左右夹逼O(n),最终O(nlogn)
bool towSum(int *arr, int len, int target)
{
int left = 0;
int right = len - 1;
qsort(arr, 0, len-1);
while(left < right)
{
if(arr[left] + arr[right] == target)
{
return true;
}
else if(arr[left] + arr[right] < target)
{
left++;
}
else
{
right--;
}
}
return false;
}
(2)SingleNumber
描述
Givenanarrayofintegers,everyelementappearstwiceexceptforone.Findthatsingleone.
Note:
Youralgorithmshouldhavealinearruntimecomplexity.Couldyouimplementitwithoutusingextramemory?
分析
异或,不仅能处理两次的情况,只要出现偶数次,都可以清零。
C++Code
1
2
3
4
5
6
7
8
9
10
11
12
13
// LeetCode, Single Number
// 时间复杂度 O(n),空间复杂度 O
(1)
class Solution
{
public:
int singleNumber(int A[], int n)
{
int x = 0;
for (size_t i = 0; i < n; ++i)
x ^= A[i];
return x;
}
};
(3)SearchinRotatedSortedArray
题目意思:
给定一个已排序数组,旋转了几次的,然后在这个旋转的数组里面查找一个目标值。
分析
二分查找,难度主要在于左右边界的确定。
C++Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
// LeetCode, Search in Rotated Sorted Array
// 时间复杂度 O(log n),空间复杂度 O
(1)
class Solution
{
public:
int search(int A[], int n, int target)
{
int first = 0, last = n;
while (first !
= last)
{
const int mid = (first + last) / 2;
if (A[mid] == target)
return mid;
if (A[first] <= A[mid])
{
if (A[first] <= target && target < A[mid])
last = mid;
else
first = mid + 1;
}
else
{
if (A[mid] < target && target <= A[last - 1])
first = mid + 1;
else
last = mid;
}
}
return -1;
}
};
5、二叉树
二叉树的基本概念:
(1)度:
某节点所拥有的子树的个数称为该节点的度;树中各个节点读的最大值称为该树的度。
(2)节点的层数、树的深度:
规定根节点的层数为1,对于其余任何节点,若某节点在第k层,则其孩子节点在第k+1层。
树中所有节点的最大层数称为树的深度,也称为树的高度。
(3)满二叉树:
在一颗二叉树中,如果所有分支节点都存在左子树和右子树,并且所有叶子都在同一层上,这样的二叉树称为满二叉树。
(4)完全二叉树
对一颗具有n个节点的二叉树按层序编号,如果编号为i(1<=i<=n)的节点与同样深度的满二叉树中编号为i的节点在二叉树中的位置完全相同,则这颗二叉树称为完全二叉树。
(5)二叉查找树
二叉查找树,或者是一颗空的二叉树,或者是具有如下性质的二叉树:
(1)若它的左子树不空,则左子树上所有节点的值均小于根结点的值。
(2)若它的右子树不空,则右子树上所有节点的值均大于根节点的值
(3)它的左右子树也都是二叉查找树。
二叉树解题思路:
主要是通过递归解决问题。
见到二叉树的题目,优先从递归方向考虑。
递归都需要返回的,考虑好返回的边界条件是什么,一般是当节点是空的时候就返回。
(1)二叉树的遍历(递归的比较简单,上网看看)
非递归前序:
使用栈实现
C++Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// LeetCode, Binary Tree Preorder Traversal
// 使用栈,时间复杂度 O(n),空间复杂度 O(n)
class Solution
{
public:
vector
{
vector
const TreeNode *p;
stack
p = root;
if (p !
= nullptr) s.push(p);
while (!
s.empty())
{
p = s.top();
s.pop();
result.push_back(p->val);
if (p->right !
= nullptr) s.push(p->right);
if (p->left !
= nullptr) s.push(p->left);
}
return result;
}
};
非递归中序遍历:
使用栈实现
C++Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// LeetCode, Binary Tree Inorder Traversal
// 使用栈,时间复杂度 O(n),空间复杂度 O(n)
class Solution
{
public:
vector
{
vector
const TreeNode *p = root;
stack
while (!
s.empty() || p !
= nullptr)
{
if (p !
= nullptr)
{
s.pu
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 数据结构 常见 编程 小结 解析
![提示](https://static.bdocx.com/images/bang_tan.gif)