// 1.基本设计思想
// 三次逆序法。将数组[x1,x2...xp]前p个逆序,再数组[xp+1,xp+2...xn]后n-p个逆序,最后数组整体逆序。
// 2.C/C++算法
void Reverse(int* arr, int l, int r) {
while (l < r) {
std::swap(arr[l++], arr[--r]);
}
}
void ShiftP(int* arr, int n, int p) {
Reverse(arr, 0, p);
Reverse(arr, p, n);
Reverse(arr, 0, n);
}
// 测试
int main() {
int arr[]{ 1,2,3,4,5,6,7,8,9 };
ShiftP(arr, 9, 5);
for (int i = 0; i < 9; ++i)
std::cout << arr[i] << ' ';
std::cout << std::endl;
return 0;
}
// 3.时间复杂度O(N),空间复杂度O(1)
// 1.双指针法。指针pa指向数组a的起始位置,指针pb指向数组b的起始位置,设置cnt=n作为计数器,每当淘汰一个数不可能是中位数时cnt就减一
// 使用一个循环,循环内进行其中一个指针后移动,移动规则:若a[pa]
// 直至cnt==0,结束循环
// 最后进行中位数的判别:
// 1)若pa==0,说明b数组所有数都大于a数组,中位数就是b数组最后一个元素
// 2)若pb==0,说明a数组所有数都大于b数组,中位数就是a数组最后一个元素
// 3)否则,中位数就是max(a[pa-1],b[pb-1])
// 2.C/C++算法
int FindMid(int* a, int* b, int n) {
int pa = 0, pb = 0;
int cnt = n;
while (cnt) {
if (a[pa] < b[pb]) {
++pa;
} else {
++pb;
}
--cnt;
}
if (pa == 0) return b[n-1];
if (pb == 0) return a[n-1];
return std::max(a[pa - 1], b[pb - 1]);
}
int main() {
int a[]{ 11,13,15,17,19 };
int b[]{ 2,4,6,19,20 };
std::cout << FindMid(a, b, 5) << std::endl;
return 0;
}
// 3.时间O(N),空间O(1)
// 1.基本设计思想
// 由于a[i]
// 从前往后依次遍历数组a,
// 1)若a[i]<0,说明这个数字是用于计数的,跳过
// 2)若a[i]==i,即该数字首次出现且出现其应该被计数的位置,设置a[i]=-1,表示数字i出现了一次
// 用变量tmp=a[a[i]],记录其计数位置上的数字
// 3)若tmp<0,说明计数位上的数字用于计数,--a[a[i]],数字i出现的次数+1
// 4)若tmp>=0,a[a[i]]=-1进行数字i的首次计数,同时a[i]=tmp,将计数位上的数字移动到a[i]位置,同时--i,以便下次循环依旧对a[i],即目前的tmp进行计数
// 2.C/C++算法
int FindMajor(int* a, int n) {
for (int i = 0; i < n; ++i) {
if(a[i]<0) continue;
if (a[i] == i) {
a[i] = -1;
continue;
}
int tmp = a[a[i]];
if (tmp < 0) --a[a[i]];
else {
a[a[i]] = -1;
a[i] = tmp;
--i;
}
}
int res = 0, cnt = 0;
for (int i = 0; i < n; ++i) {
if (a[i] < cnt) {
res = i;
cnt = a[i];
}
}
if((-cnt)>n / 2)
return res;
return -1;
}
int main() {
//int a[]{ 0,5,5,3,5,7,5,5 };
int a[]{ 0,5,5,3,5,1,5,7 };
std::cout << FindMajor(a, 8);
return 0;
}
// 3.时间O(N),最坏情况下会循环2N次。空间O(1)
// 1.基本设计思想
// 使用一个长度为n+2的辅助数组来标记对应的正整数是否出现,如vis[i]=1,表示数字i出现过,vis[i]=0,则表示数字i没出现过
// 随后从1开始遍历vis数字,遇到vis[i]==0,就说明找到了未出现的最小正整数
// 2.C/C++算法
int FindMinPos(int* a, int n) {
vector<int> vis(n + 2, 0);
for (int i = 0; i < n; ++i) {
if (a[i] > 0 && a[i] <= n)
vis[a[i]] = 1;
}
for (int i = 1; i <= n+1; ++i)
if (vis[i]==0) return i;
return -1;
}
int main()
{
//int a[]{ -5,3,2,3 };
int a[]{ 1,2,3,4 };
std::cout << FindMinPos(a, 4);
return 0;
}
// 3.时间复杂度O(N),空间O(1)
// 2020
// 1.算法设计思想
// 可以发现,距离D只会最小值和最大值有关,即D=(maxv-minv)*2
// 设置三个指针i,j,k分别指向三个数组的起始位置,每次找出三个中最小的元素和最大的元素,进行距离的计算,随后该数组上的指针++,指向下一个元素
// 一直循环,直到某一个数组遍历结束就停止,因为再往后距离差距只会越来越大,因为最小值已经固定了,最大值会越来越大
// 2.C/C++
int MinDistance(vector<int> s1, vector<int> s2, vector<int> s3) {
int n1 = s1.size(), n2 = s2.size(), n3 = s3.size();
int res = INT_MAX;
int minv = INT_MAX, maxv = INT_MIN;
int i, j, k;
i = j = k = 0;
while (i < n1 && j < n2 && k < n3) { // 只要有一个数组遍历完了,就可以结束了,因为再往后差距只会越来越大
minv = min({ s1[i],s2[j],s3[k] });
maxv = max({ s1[i],s2[j],s3[k] });
res = min(res, (maxv - minv) * 2);
if (s1[i] == minv) {
++i;
} else if (s2[j] == minv) {
++j;
} else {
++k;
}
}
return res;
}
int main() {
vector<int> s1{ -1,0,9 }, s2{ -25,-10,10,-11 }, s3{ 2,9,17,30,41 };
cout << MinDistance(s1, s2, s3);
return 0;
}
// 3. 时间O(N) 空间O(1)
// 1.先遍历一遍,求出链表的长度n,再从头遍历n-k个元素,此时即是倒数第k个元素
// 2.实现步骤:用一变量cur指向首个实际元素,同时使用变量n(初始化为0)开始计数链表的长度,使用cur=cur->link依次往后遍历
// n=n-k,此时n就是需要从前往后遍历的个数。cur=head->link,重新指向首个实际元素,遍历n个后,cur的指向即为倒数第k个节点,return cur->data即可
// 3.C/C++
struct node {
int data;
node* link;
node(int da = 0, node* li = nullptr) :data(da), link(li) {}
};
int get_k_ele(node* head, int k) {
node* cur = head->link;
int n = 0;
while (cur) {
++n;
cur = cur->link;
}
n = n - k;
cur = head->link;
while (n--) {
cur = cur->link;
}
return cur->data;
}
int main() {
node* head = new node(0, new node(1, new node(2, new node(3, new node(4, new node(5, nullptr))))));
cout << get_k_ele(head, 2) << endl;
return 0;
}
// 1.基本设计思想
// 设置双指针p1指向str1首实际元素,p2指向str2首实际元素,
// 使用while进行循环,循环条件为p1 != p2
// p1和p2同时后移,
// 若某个时刻移动之后,p1为NULL,那么p1指向str2首实际元素
// 若p2为NULL,那么p2指向str2首实际元素
// 当循环终止后,p1的指向即为共同后缀的起始位置
// 2.C/C++
struct node {
char data;
node* link;
node(int da = 0, node* li = nullptr) :data(da), link(li) {}
};
node* get_same_suffix(node* str1, node* str2) {
node* p1 = str1->link;
node* p2 = str2->link;
while (p1 != p2) {
if (p1 && p2) {
p1 = p1->link;
p2 = p2->link;
}
if (p1 == nullptr) {
p1 = str2->link;
} else if(p2==nullptr) {
p2 = str1->link;
}
}
return p1;
}
int main()
{
node* cur = new node('i', new node('n', new node('g')));
node* str1 = new node(0,new node('l', new node('o', new node('a', new node('d', cur)))));
node* str2 = new node(0,new node('b', new node('e', cur)));
cout << get_same_suffix(str1, str2)->data << endl;
return 0;
}
// 3.时间复杂度O(N),N为两条链表的长度之和,设str1表长为n1,str2表长n2,那么该算法固定遍历2*(n1+n2)次
// 1.设计思想
// 设置一个标记数组,vis[i]=true表示绝对值是i的节点已近出现过了,初始全为false
// 从前往后遍历链表,若vis[abs(data)]==false,说明绝对值没有出现过的,进行标记vis[abs(data)]=true
// 若vis[abs(data)]==true,绝对值出现过,进行删除
// 2.结点定义
struct node {
int data;
node* link;
node(int da = 0, node* li = nullptr) :data(da), link(li) {}
};
// 3.C/C++
node* remove_same_node(node* head,int n) {
vector<bool> vis(n + 1, false);
node* cur = head;
while (cur && cur->link) {
if (vis[abs(cur->link->data)]) { // 绝对值相等的出现过,删除
node* del = cur->link;
cur->link = cur->link->link;
delete del;
} else { // 没出现过,标记一下
vis[abs(cur->link->data)] = true;
cur = cur->link;
}
}
return head;
}
int main()
{
node* head = new node(0, new node(1, new node(1, new node(3, new node(2, new node(3, nullptr))))));
head = remove_same_node(head, 5)->link;
while (head) {
cout << head->data << ' ';
head = head->link;
}
cout << endl;
return 0;
}
// 4. 时间O(m),空间O(n)
// 1.设计思想
// 使用快慢指针定位到链表的中间位置,再反转后半部分链表,随后用两个指针i,j,分别指向前半部分的表头和后半部分的表头,最后进行两个链表的交叉合并
// 2.C/C++
typedef struct node {
int data;
struct node* next;
node(int da = 0, node* li = nullptr) :data(da), next(li) {}
}NODE;
NODE* re_sort(NODE* head) {
NODE* fast = head, *low = head;
// 使用快慢指针找到中间位置,循环退出之后,
while (fast && fast->next) {
fast = fast->next;
low = low->next;
if (fast) {
fast = fast->next;
}
}
// 此时low下一个结点即是后一半链表的首结点,这里规定后一半的长度为n/2(下取整)
NODE* cur = low->next;
low->next = nullptr;
// 反转后半部分链表
// 往后遍历,进行头插
while (cur) {
NODE* ne = cur->next;
cur->next = low->next;
low->next = cur;
cur = ne;
}
low = low->next;
cur = head->next;
while (low) {
NODE* low_next = low->next;
low->next = cur->next;
cur->next = low;
cur = low->next;
low = low_next;
}
if (cur) {
cur->next = nullptr;
}
return head;
}
int main()
{
node* head = new node(0, new node(1, new node(2, new node(3, new node(4, new node(5, nullptr))))));
head = re_sort(head)->next;
while (head) {
cout << head->data << ' ';
head = head->next;
}
return 0;
}
// 3.时间O(N),空间O(1)