此时定义了三个变量,一个为dst,prev和cur,那么为什么会这么想呢?
int removeDuplicates(int* nums, int numsSize)
{
//数组在一开始的时候有可能为空,这个情况也一定要考虑进去
if (numsSize == 0)
return 0;
int prev = 0, cur = 1, dst = 0;
while (cur < numsSize) //用cur来判断,因为他最终会越界,作为循环来结束的一个判断标志,prev指向数组中下标为0的元素,cur指向数组中下标为1的元素
{
if (nums[prev] != nums[cur])
{
nums[dst] = nums[prev];
prev++;
dst++;
cur++;
}
else
{
prev++;
cur++;
}
}
//此时prev和cur的值是不相等的,但是上面你只返回了prev的值,
//最后一个cur值也是需要返回的
nums[dst] = nums[prev];
dst++;
return dst;
}
提示:
1 <= A.length <= 10000
0 <= A[i] <= 9
0 <= K <= 10000
如果 A.length > 1,那么 A[0] != 0
1.考虑K这个值为几位数
2.结果要求输出的是一个数组,但是你这个数组应该开辟多大的呢?(最大的那个数组元素位数加1,不可能在超过这个数字了,是在不行其实是可以直接开辟一个6位整形的空间)
3.返回的那个数组来存储你的每个位数,但是你会发现是先从个位数相加的,所以你的返回数组的顺序是反的,最终需要在颠倒过来。
int* addToArrayForm(int* A, int ASize, int K, int* returnSize)
{
//计算K是多少位的
int KSize = 0;
int kNum = K; // 如果不加这个你会发现,你到最后把K的数值已经改变了,就找不到了
while (kNum)
{
KSize++;
kNum /= 10; // 这里也在提示不要轻易的修改掉原来的K值,因为这里会发生K值的变化
}
int len = ASize > KSize ? ASize : KSize;
int* retArr = (int*)malloc(sizeof(int)*(len+1)); //返回数组的长度,但是这里还有一个小技巧,你会发现题目下面是有限制条件的,0<K<10000
//所以你就直接开辟一个6位数数组大小空间就好了。
//A []
//K
int Ai = ASize - 1; //A数组的最后一位
int reti = 0;
int nextNum = 0;//进位
while (len--)
{
int a = 0;
if (Ai >= 0) // A的数组短,会先走完
{
a = A[Ai];
Ai--;
}
int ret = a + K % 10 + nextNum;
K /= 10;
if (ret > 9)
{
ret -= 10;
nextNum = 1;
}
else
{
nextNum = 0;
}
retArr[reti] = ret;
reti++;
}
if (nextNum == 1)
{
retArr[reti] = 1;
reti++;
}
//逆置
int left = 0;
int right = reti - 1;
while (left < right)
{
int tmp = retArr[left];
retArr[left] = retArr[right];
retArr[right] = tmp;
left++;
right--;
}
*returnSize = reti;
return retArr;
}
这个题很巧妙的使用了prev和cur指针,开始的时候perv这个指针是在NULL地方的。而且要考虑到一开始就是你要找的那个val值的情况。
struct ListNode* removeElements(struct ListNode* head, int val)
{
//对于head不要轻易的作出修改,因为他最终让你返回的是这个单链表的头,所以能不修改尽量不要修改
struct ListNode* prev = NULL,*cur = head;
while(cur != NULL)
{
if(cur->val == val) // 这个地方的逻辑是混乱的,需要重新看视频理解代码
{
if(cur == head) //第一个值就是val
{
head = cur->next;
free(cur);
cur = head;
}
else//(不是第一个位置为6的可能性)
{
prev->next=cur->next;
free(cur);//如果不添加最后这行代码,你就会发现此时cur已经被free变成野指针了,你在上去
//进行使用它,就会报错
cur = prev->next; // 原来会写cur = cur->next,这样写也是错误的,因为你会发现,你的cur已经被释放了,然后你在下一行中还要使用它,所以我们使用prev来定义它此时的cur
}
}
else
{
prev = cur;
cur = cur->next;
}
}
return head;
}
第二种方法:三指针翻转法
struct ListNode* reverseList(struct ListNode* head)
{
if(head == NULL || head->next == NULL)
{
return head;
}
struct ListNode* n1 = NULL;
struct ListNode* n2 = head;
struct ListNode* n3 = head->next;
while(n2 != NULL)
{
n2->next = n1;
n1 = n2;
n2 = n3;
//循环的条件是判断n2,但是当n2指向链表的最后一个结点的时候,n3已经在NULL的位置了,如果你不它加以判断,而是直接的解引用,程序就会崩溃。
if(n3 != NULL)
{
n3 = n3->next;
}
}
return n1;
}
对于这个题就比较有意思了,定义了一个cur和newHead的NULL空指针,此时相当于我把原先链表的头拿下来然后进行头插在newHead的前面
struct ListNode* reverseList(struct ListNode* head)
{
struct ListNode* newHead = NULL;
//然后我进行头插,插到我新建的这个newhead前面
struct ListNode* cur = head;
while (cur != NULL)
{
struct ListNode* next = cur->next;
cur->next = newHead;
newHead = cur;
cur = next;
}
return newHead;
}
//首先让小的那个做为头,然后并的比较,当有一个链表为NULL的时候就停止了,剩下的直接拉下来就好了
struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2)
{
//当着两个都不为空的时候再回进入到第三个if里面
if(l1 == NULL)
return l2;
if(l2 == NULL)
return l1;
if(l1 == NULL && l2 == NULL)//这样写就会很轻易的理解对于l1和l2是由4种可能性的。
return ;
struct ListNode* head = NULL,*tail = NULL;
//带哨兵位的头结点,没有实际的数据
//你如果不进行上面的判断,你会发现,你在下面用到了结构体的解引用,程序直接有可能崩溃
if(l1->val < l2->val)
{
head = tail = l1;
l1 = l1->next;
}
else
{
head = tail = l2;
l2 = l2->next;
}
//取较小的值进行尾插
while(l1 && l2)
{
if(l1->val < l2->val)
{
tail->next = l1;
l1 = l1->next;
}
else
{
tail->next = l2;
l2 = l2->next;
}
tail = tail->next;
}
if(l1)
{
tail->next = l1;
}
else
{
tail->next = l2;
}
return head;
}