正式开启数据结构+算法研究的历程,准备好一年后的面试。下面的解法不一定是最优解,只求能力提升,会定期更新~~
1 | 2 | 19 | 20 | 21 | 24 |
---|---|---|---|---|---|
35 | 83 | 86 | 94 | 100 | 101 |
102 | 103 | 104 | 108 | 110 | 111 |
112 | |||||
– | – | – | – | – | – |
122 | 136 | 141 | 142 | 144 | 155 |
160 | |||||
– | – | – | – | – | – |
191 | 202 | 203 | 206 | 226 | 231 |
235 | 237 | 257 | 268 | 371 | 876 |
– | – | – | – | – | – |
938 | 5673 |
(暴力算法)
此题目类似冒泡排序法,使用暴力算法解题,双重循环遍历求得目标值,每次循环判断是否满足条件,如果满足,则记录下标。(返回结果的时候注意返回returnSize)。
/**
1. Note: The returned array must be malloced, assume caller calls free().
*/
int* twoSum(int* nums, int numsSize, int target, int* returnSize){
int *a = (int *)malloc(sizeof(int)*2);
for (int i = 0; i < numsSize-1; i++) {
for (int j = i + 1; j < numsSize; j++) {
if (nums[j] + nums[i] == target) {
a[0] = i;
a[1] = j;
*returnSize = 2;
return a;
}
}
}
*returnSize = 0;
return 0;
}
代码可能写的比较啰嗦,但是逻辑是没问题的,每位相加记录进位数,直到两个都结束,结束后检查进位填补结点。
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
ListNode* res = new ListNode();
ListNode rest;
rest.next = res;
int memo = 0;
while(l1 != NULL && l2 != NULL) {
int temp = memo + l1->val + l2->val;
if(temp > 9){
memo = 1;
}else {
memo = 0;
}
ListNode* kk = new ListNode();
kk->val = (temp) % 10;
res->next = kk;
res = res->next;
l1 = l1->next;
l2 = l2->next;
}
while(l1 != NULL){
int temp = memo + l1->val;
if(temp > 9){
memo = 1;
}else {
memo = 0;
}
ListNode* kk = new ListNode();
kk->val = (temp) % 10;
res->next = kk;
res = res->next;
l1 = l1->next;
}
while(l2 != NULL){
int temp = memo + l2->val;
if(temp > 9){
memo = 1;
}else {
memo = 0;
}
ListNode* kk = new ListNode();
kk->val = (temp) % 10;
res->next = kk;
res = res->next;
l2 = l2->next;
}
if(memo == 1){
ListNode* kk = new ListNode();
kk->val = 1;
kk->next = NULL;
res->next = kk;
}
return rest.next->next;
}
};
这道题用暴力的方法,注意要添加一个虚拟头结点来处理链表为空或者为一个结点的情况。
这里也可以用双指针的方法一遍过,让两个间距为n的指针平行移动找到要删除的即可,这里就不实现了。睡觉了,晚安~
struct ListNode* removeNthFromEnd(struct ListNode* head, int n){
struct ListNode* test = (struct ListNode*)malloc(sizeof(struct ListNode));
test->next = head;
struct ListNode p; // 用一个结点p来记录链表
p.next = test;
int num = 0;
while(head!=NULL){
num++;
head = head->next;
}
for(int i=0;i<num-n;i++){
test = test->next;
}
if(test->next!=NULL){
test->next = test->next->next;
}
return p.next->next;
}
这里用了线性栈–一个数组来表示栈,将左括号放入栈中,计数器加一,当遇到右括号的时候进行匹配,并且使计数器的值减一,最终判断计数器的值是否被清空。
bool isValid(char * s){
int n = strlen(s);
char *arr = (char *)malloc(sizeof(char)*n+1);
memset(arr,0,n);
int j = 1;
for(int i = 0;i<n;i++){
if(s[i] == '{' || s[i] == '(' || s[i] == '['){
arr[j] = s[i];
j++;
}else if((s[i] == '}' && arr[j-1] == '{') || (s[i] == ')' && arr[j-1] == '(') || (s[i] == ']' && arr[j-1] == '[')){
j--;
}else{
return false;
}
}
if(j == 1){
return true;
}
return false;
}
1.自用的方法是暴力算法,性能很低下。。。最古老的办法进行链表的逐个排序放入,注意操作链表的写法。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2){
struct ListNode *temp = (struct ListNode *)malloc(sizeof(struct ListNode));
struct ListNode *Head = (struct ListNode *)malloc(sizeof(struct ListNode));
temp->next = NULL;
if(l1->val < l2->val){
struct ListNode *swap = (struct ListNode *)malloc(sizeof(struct ListNode));
swap->val = l1->val;
temp->next = swap;
temp = temp->next;
}else if(l1->val >= l2->val){
struct ListNode *swap = (struct ListNode *)malloc(sizeof(struct ListNode));
swap->val = l2->val;
temp->next = swap;
temp = temp->next;
}
return Head;
}
题目不是很难,但是反映的问题比较多,首先要记住虚拟头结点的重要性,然后链表换顺序需要一个虚拟头结点记住初始位置。
struct ListNode* swapPairs(struct ListNode* head){
struct ListNode p;
p.next = head;
struct ListNode* temp = &p;
while((temp->next!=NULL)&&(temp->next->next!=NULL)){
struct ListNode* s1 = temp->next;
struct ListNode* s2 = temp->next->next;
temp->next = s2;
s1->next = s2->next;
s2->next = s1;
temp = temp->next->next;
}
return p.next;
}
一道简单题,用普通的搜索方法就可以做出;
可用来复习二分法查找。
int searchInsert(int* nums, int numsSize, int target){
int i;
for(i = 0;i<numsSize;i++){
if(nums[i] == target){
return i;
}
if(nums[i] > target){
return i;
}
}
return i;
}
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* deleteDuplicates(struct ListNode* head){
struct ListNode* cur = head;
while(cur != NULL){
struct ListNode* rear = cur->next;
if(rear == NULL){
return head;
}
if(cur->val == rear->val){
cur->next = rear->next;
}
else{
cur = cur->next;
}
}
return head;
}
这题实现起来比较麻烦,需要不停地维护两个结点,并且需要一个标志来记录是否出现大于等于特殊值的结点。代码最终实现效果很好,几乎都是超过所有人。
struct ListNode* partition(struct ListNode* head, int x){
struct ListNode* temp = (struct ListNode*)malloc(sizeof(struct ListNode));
temp->next = head;
struct ListNode p;
p.next = temp;
bool flag = false; // 用来标志是否出现大于等于特殊值的结点,若没出现,前面不用动
struct ListNode* ram; // 用来标志前面最新的小节点,即下一次前移要插进该结点的后面
struct ListNode* rbm; // 用来标志第一次出现的大于等于特殊值的结点
ram = temp; // 排除链表结点个数少的情况
while(temp->next != NULL){
if((temp->next->val<x)&&!flag){
// 未出现大于等于特殊值的结点,一直往后推进,同时不断更新ram
ram = temp->next;
temp = temp->next;
}else if(temp->next->val>=x){
// 出现了特殊结点,修改标志,记录rbm
// 后续再出现,不做任何改动
if(!flag){
flag = true;
rbm = temp->next;
}
temp = temp->next;
}else if((temp->next->val<x)&&flag){
// 已出现特殊结点且当前结点小于特殊值,做顺序修改,具体过程建议画图
ram->next = temp->next;
temp->next = temp->next->next;
ram->next->next = rbm;
ram = ram->next;
}
}
return p.next->next;
}
本题有两种做法,一种是中规中矩的递归,另一种是看官方题解给的方法,叫做Mirrors方法,代码附在下面,目前还没有办法能写出这个算法。。。。加油。
void inorder(struct TreeNode* root,int *arr,int *num){
if(root == NULL){
return;
}
inorder(root->left,arr,num);
arr[(*num)++] = root->val;
inorder(root->right,arr,num);
}
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* inorderTraversal(struct TreeNode* root, int* returnSize){
int *arr = malloc(sizeof(int)*500);
*returnSize = 0;
inorder(root,arr,returnSize);
return arr;
}
int* inorderTraversal(struct TreeNode* root, int* returnSize) {
int* res = malloc(sizeof(int) * 501);
*returnSize = 0;
struct TreeNode* predecessor = NULL;
while (root != NULL) {
if (root->left != NULL) {
// predecessor 节点就是当前 root 节点向左走一步,然后一直向右走至无法走为止
predecessor = root->left;
while (predecessor->right != NULL && predecessor->right != root) {
predecessor = predecessor->right;
}
// 让 predecessor 的右指针指向 root,继续遍历左子树
if (predecessor->right == NULL) {
predecessor->right = root;
root = root->left;
}
// 说明左子树已经访问完了,我们需要断开链接
else {
res[(*returnSize)++] = root->val;
predecessor->right = NULL;
root = root->right;
}
}
// 如果没有左孩子,则直接访问右孩子
else {
res[(*returnSize)++] = root->val;
root = root->right;
}
}
return res;
}
(递归算法)
1.先判断节点是否拥有左右孩子,同时为空则返回true,只有一个则返回false
2.如果两个节点的值不相等,则返回false
3.如果没有return,函数最终利用递归法,将对应的左孩子和右孩子进行递归返回值。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
bool isSameTree(struct TreeNode* p, struct TreeNode* q){
if(p == NULL && q == NULL){
return true;
}
if(p == NULL || q == NULL){
return false;
}
if(p->val != q->val){
return false;
}
return isSameTree(p->left,q->left)&&isSameTree(p->right,q->right);
}
(递归算法)
此题应该特别写一个函数,函数含有两个参数,左子树和右子树,函数内部使用递归。
1.先判断传入的两个节点是否同时为空,或者其中一个为空,前者return true,后者return false
2.如果上述过程没有return,则判断左节点的右孩子和右节点的左孩子&&右节点的右孩子和左节点的左孩
最重要的是找到递归点。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
bool checkSymmetric(struct TreeNode* lroot,struct TreeNode* rroot){
if(lroot == NULL && rroot == NULL){
return true;
}
if(lroot == NULL || rroot == NULL){
return false;
}
if(lroot->val == rroot->val){
return checkSymmetric(lroot->left,rroot->right)&&checkSymmetric(lroot->right,rroot->left);
}
return false;
}
bool isSymmetric(struct TreeNode* root){
return checkSymmetric(root,root);
}
肝了两天,解决了这个层序遍历的个人解法!
我的思路是递归遍历层数的时候带上一个层数记录器,利用这个记录器将结点信息保存在二维容器对应层。先是用C语言做,很不理想,因为C没有动态容器这种东西,后来使用了C++的vector,很轻松的解决了,算法速度很快,比队列快了一丢丢,优点在于,思路极其简单!
// 个人解法:
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> res;
int pos = 0;
Tranverse(root,pos,res);
return res;
}
void Tranverse(TreeNode* root,int pos,vector<vector<int>> &arr){
if(root == NULL){
return;
}
if(pos>=arr.size()){
arr.push_back(vector<int> ());
}
arr[pos].push_back(root->val);
Tranverse(root->left,pos+1,arr);
Tranverse(root->right,pos+1,arr);
}
};
和上面几个层序遍历类似,这题的思路是增加一个层数指示器,按照正常的顺序存进队列,然后按层存入容器,偶数层逆序存入容器。
class Solution {
public:
vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
vector<vector<int>> res;
queue<TreeNode*> q;
int level = 0;
if(root == NULL){
return res;
}
q.push(root);
while(!q.empty()){
vector<int> newbar;
int size = q.size();
for(int i=0;i<size;i++){
TreeNode* cur = q.front();
q.pop();
newbar.push_back(cur->val);
if(cur->left != NULL){
q.push(cur->left);
}
if(cur->right != NULL){
q.push(cur->right);
}
}
if(level++ % 2 == 1){
reverse(newbar.begin(),newbar.end());
}
res.push_back(newbar);
}
return res;
}
};
定义一个max函数,递归遍历每一个叶子节点,经过一个就加一,return最大的数。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
int max(int a,int b){
if(a>b){
return a;
}else{
return b;
}
}
int maxDepth(struct TreeNode* root){
if(root == NULL){
return 0;
}
return 1 + max(maxDepth(root->left),maxDepth(root->right));
}
本题类似102题,102题我用的是自己的方法,那么这题用的就是基础的队列方法,没啥好说的看代码。
class Solution {
public:
vector<vector<int>> levelOrderBottom(TreeNode* root) {
queue<TreeNode*> q;
q.push(root);
vector<vector<int>> smallv;
if(root == NULL){
return smallv;
}
while(!q.empty()){
int size = q.size();
vector<int> newv;
for(int i=0;i<size;i++){
struct TreeNode* cur = q.front();
q.pop();
newv.push_back(cur->val);
if(cur->left != NULL){
q.push(cur->left);
}
if(cur->right != NULL){
q.push(cur->right);
}
}
smallv.push_back(newv);
}
reverse(smallv.begin(),smallv.end());
return smallv;
}
};
先看题目,这道题给出的是一个有序数组,所以我们只要每次选择最中间的元素视为根结点返回即可,过程中需要控制边界。
struct TreeNode* constructor(int* nums,int left,int right){
if(left > right){
return NULL;
}
struct TreeNode* root = (struct TreeNode*)malloc(sizeof(struct TreeNode));
int mid = (left + right + 1)/2;
root->val = nums[mid];
root->left = constructor(nums,left,mid-1);
root->right = constructor(nums,mid+1,right);
return root;
}
struct TreeNode* sortedArrayToBST(int* nums, int numsSize){
return constructor(nums,0,numsSize-1);
}
思路比较简单,平衡二叉树的每一棵子树都是平衡二叉树。使用双重递归的方法,目前比较复杂,等待以后优化。
int height(struct TreeNode* root){
if(root == NULL){
return 0;
}
return fmax(height(root->left),height(root->right))+1;
}
bool isBalanced(struct TreeNode* root){
if(root == NULL){
return true;
}
return (fabs(height(root->left)-height(root->right)) <= 1)&&(isBalanced(root->left))&&(isBalanced(root->right));
}
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
int minDepth(struct TreeNode* root){
if(root == NULL){
return 0;
}
if(root->left == NULL && root->right == NULL){
return 1;
}
if(root->left != NULL && root->right == NULL){
return 1+minDepth(root->left);
}
if(root->left == NULL && root->right != NULL){
return 1+minDepth(root->right);
}
return 1+(minDepth(root->left)<minDepth(root->right)?minDepth(root->left):minDepth(root->right));
}
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
bool hasPathSum(struct TreeNode* root, int sum){
if(root == NULL){
return false;
}
if(root->left == NULL && root->right == NULL){
return root->val == sum;
}
return hasPathSum(root->left,sum-root->val) || hasPathSum(root->right,sum-root->val);
}
int maxProfit(int* prices, int pricesSize){
if(pricesSize == 0){
return 0;
}
int sum = 0;
for(int i = 0;i < pricesSize - 1;i++){
if(prices[i]<prices[i+1]){
sum += prices[i+1] - prices[i];
}
}
return sum;
}
第一次使用位运算,还用到了异或^,太骚了,这三行代码解决。
任何数与0异或结果为本身,
任何数与自身异或结果为0;
class Solution {
public:
int singleNumber(vector<int>& nums) {
int res = 0;
for(auto i:nums) res ^= i;
return res;
}
};
本题适合使用快慢指针来求解,如果存在环,快指针总会撞到慢指针。
bool hasCycle(struct ListNode *head) {
if(head == NULL || head->next == NULL){
return false;
}
struct ListNode *slow = head;
struct ListNode *fast = head->next;
while((fast != NULL) && (fast->next != NULL)){
slow = slow->next;
fast = fast->next->next;
if(fast==slow){
return true;
}
}
return false;
}
本题较此题的母题加大了难度,母题判断是否有环,本题则返回环的入口结点。
同样是使用快慢指针的思路,快指针一次走两步,慢指针一次走一步,在环内有一个相遇点。
先进行数学归纳推导:
如图所示,A为环前表长,B为相遇点前的长度,C为相遇点到入口点的长度。
假设n为在圈内循环的次数,则:
先分析快指针步数:
Step1 = A + n × ( B + C ) + B = A + ( n + 1 ) × B + n × C
再分析慢指针步数:
Step2 = A + B
两者数量关系为2倍: Step2 × 2 = Step1
则 2 ×( A + B ) = A + ( n + 1 ) × B + n × C
得到
A =( n - 1 )× ( B + C )+ C
即入口前长度A等于从n圈后加C,初始位置为相遇点,则n圈后加C的位置为入环结点。
于是我们让一个新的结点从head开始和slow一起跑,最终相遇在入环结点。
struct ListNode *detectCycle(struct ListNode *head) {
struct ListNode *slow = head;
struct ListNode *fast = head;
while(fast!=NULL){
if(fast->next == NULL) return NULL;
slow = slow->next;
fast = fast->next->next;
if(slow == fast){
struct ListNode *extra = head;
while(extra!=slow){
slow = slow->next;
extra = extra->next;
}
return extra;
}
}
return NULL;
}
nnd,好不容易会了递归,还有迭代。。。好不容易会了迭代,还有Morris。。。。。
class Solution {
public:
void Tranverse(TreeNode* root,vector<int> &res) {
if(root == nullptr) {
return;
}
res.push_back(root->val);
Tranverse(root->left,res);
Tranverse(root->right,res);
}
vector<int> preorderTraversal(TreeNode* root) {
vector<int> res;
Tranverse(root,res);
return res;
}
};
在栈中使用到了辅助栈,负责记录主栈的最小值,起到用空间换取时间的效果。如果不用辅助栈,算法性能总体都很差。
typedef struct {
int arr[7700];
int top;
struct numstack *stack;
}MinStack;
typedef struct numstack{
int arr[3000];
int top;
}numstack;
/** initialize your data structure here. */
MinStack* minStackCreate() {
MinStack *st = (MinStack *)malloc(sizeof(MinStack));
st->stack = (numstack *)malloc(sizeof(numstack));
st->top = -1;
st->stack->top = -1;
return st;
}
void minStackPush(MinStack* obj, int x) {
obj->top ++;
obj->arr[obj->top] = x;
if(obj->top == 0){
obj->stack->top++;
obj->stack->arr[obj->stack->top] = x;
}else{
if(x<=obj->stack->arr[obj->stack->top]){
obj->stack->top++;
obj->stack->arr[obj->stack->top] = x;
}
}
}
void minStackPop(MinStack* obj) {
if(obj->arr[obj->top] == obj->stack->arr[obj->stack->top]){
obj->stack->top--;
}
obj->top--;
}
int minStackTop(MinStack* obj) {
int i = obj->top;
return obj->arr[obj->top];
}
int minStackGetMin(MinStack* obj) {
if(obj->stack->top == -1){
return NULL;
}
return obj->stack->arr[obj->stack->top];
}
void minStackFree(MinStack* obj) {
free(obj);
}
/**
* Your MinStack struct will be instantiated and called as such:
* MinStack* obj = minStackCreate();
* minStackPush(obj, x);
* minStackPop(obj);
* int param_3 = minStackTop(obj);
* int param_4 = minStackGetMin(obj);
* minStackFree(obj);
*/
本题比较浪漫的解法,类似快慢指针寻找环,本题是两个指针错位移动寻找共同节点。
正所谓:错的人终将走散,对的人终将重逢。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
struct ListNode *work1 = headA;
struct ListNode *work2 = headB;
while(work1!=work2)
{
if(work1)
work1 = work1->next;
else
work1 = headB;
if(work2)
work2 = work2->next;
else
work2 = headA;
}
return work2;
}
class Solution {
public:
uint32_t reverseBits(uint32_t n) {
uint32_t res = 0;
int num = 31;
while(n!= 0){
res += (n & 1) << num--;
n = n >> 1;
}
return res;
}
};
趁热打铁,学了使用位运算,真的快活!下面给出两种方法,第一种是自己想出来的,第二种是官网优化算法。只能说,太巧妙了,将n与n-1进行或运算总会将最小的1位变为0。
class Solution {
public:
int hammingWeight(uint32_t n) {
int num = 0;
while(n != 0){
if(n & 1 == 1){
num++;
}
n = n >> 1;
}
return num;
}
};
class Solution {
public:
int hammingWeight(uint32_t n) {
int num = 0;
while(n != 0){
num++;
n &= (n - 1);
}
return num;
}
};
有三种做法:1.自己的解法,贪心算法;2.哈希表解法;3.快慢指针的解法。
我的解法有两个判断条件:根据观察,递归时:1.若某次递归初始数为1,则返回 true ;2.若某次递归时初始数为4,则陷入死循环,不快乐了,返回 false 。
其中我的解法要注意的知识点是:未知位数的 int 型变量取出每位的数,用%从小往大取比较方便。
bool isHappy(int n){
if(n==1){
return true;
}
if(n==4){
return false;
}
int j=0;
int temp = n;
while(temp>0){
temp = temp/10;
j++;
}
int k=0;
for(int i=0;i<j;i++){
k = k + (n%10) * (n%10);
n = n / 10;
}
return isHappy(k);
}
struct ListNode* removeElements(struct ListNode* head, int val){
struct ListNode p;
p.next = head;
struct ListNode* cur = &p;
while (cur->next != NULL) {
if (cur->next->val == val) {
cur->next = cur->next->next;
} else {
cur = cur->next;
}
}
return p.next;
}
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* reverseList(struct ListNode* head){
struct ListNode* pre = NULL;
struct ListNode* current = head;
struct ListNode* temp;
while(current != NULL){
temp = current->next;
current->next = pre;
pre = current;
current = temp;
}
return pre;
}
/**
1. Definition for a binary tree node.
2. struct TreeNode {
3. int val;
4. struct TreeNode *left;
5. struct TreeNode *right;
6. };
*/
struct TreeNode* invertTree(struct TreeNode* root){
if(root == NULL){
return NULL;
}
struct TreeNode* temp = root->left;
root->left = root->right;
root->right = temp;
invertTree(root->left);
invertTree(root->right);
return root;
}
这题给的测试数据太坑了,题目也没有说清楚,需要注意数据类型和长度,然后要学会使用n&n-1。
class Solution {
public:
bool isPowerOfTwo(int n) {
if(n == 0){
return false;
}
long x = n;
return ((x-1) & x) == 0;
}
};
此题有两种解法,一种是两遍遍历得到两个结点的访问路径,然后逐个比较筛选;
另一种解法是:
有三种情况:
struct TreeNode* lowestCommonAncestor(struct TreeNode* root, struct TreeNode* p, struct TreeNode* q) {
while(true){
if(root->val>p->val&&root->val>q->val){
root = root->left;
}else if(root->val<p->val&&root->val<q->val){
root = root->right;
}else{
break;
}
}
return root;
}
void deleteNode(struct ListNode* node) {
node->val = node->next->val;
node->next = node->next->next;
}
采用深度遍历算法,用一个数组记录非叶结点,当访问到叶结点时将相应的序列放进数组。
void Tranverse(struct TreeNode* root,int num,int *arr,int *returnSize,char** res){
if(root == NULL){
return ;
}
if(root->left == NULL && root->right == NULL){
char* temp = (char*)malloc(sizeof(char)*1000);
int len = 0;
for(int i=0;i<num;i++){
len += sprintf(temp+len,"%d->",arr[i]);
}
sprintf(temp+len,"%d",root->val);
res[(*returnSize)++] = temp;
}else{
arr[num++] = root->val;
Tranverse(root->left,num,arr,returnSize,res);
Tranverse(root->right,num,arr,returnSize,res);
}
}
char ** binaryTreePaths(struct TreeNode* root, int* returnSize){
char** res = (char**)malloc(sizeof(char*)*1000);
int* arr = (int*)malloc(sizeof(int)*1000);
*returnSize = 0;
Tranverse(root,0,arr,returnSize,res);
return res;
}
一种做法是付出额外的空间,申请一个额外的数组来存放数字,然后改变值,通过值来判断是否缺失。
int missingNumber(int* nums, int numsSize){
int *arr = (int*)malloc(sizeof(int)*(numsSize+1));
int ans;
for(int i=0;i<numsSize+1;i++){
arr[i] = -1;
}
for(int i=0;i<numsSize;i++){
arr[nums[i]] += 1;
}
for(int j=0;j<numsSize+1;j++){
if(arr[j] != 0){
ans = j;
break;
}
}
return ans;
}
该题目是2的幂的变题,只需要在辨别2的幂的基础上区分2和4,两种思路,一是用该数异运算0xaaaaaaaa,得到一的为4的幂,可以发散至其他的题目。但是也可用%3 == 1 的方法。
class Solution {
public:
bool isPowerOfFour(int n) {
long x = n;
if(n <= 0) return false;
return ((n-1 & n) == 0) && (n%3==1);
}
};
利用加法器的原理,先用异或算加过的位数,再用或算出进位,循环,直到为零。
class Solution {
public:
int getSum(int a, int b) {
unsigned long x = a,y = b;
while(x != 0){
long temp = x^y;
x = (x&y) << 1;
y = temp;
}
return y;
}
};
本题两种思路,一种是暴力求解,先得到链表长度,再返回一半的链表;
另一种是用快慢指针,慢指针走到一半快指针走到头。下面给出了两种方法的代码。原则上两种方法的性能是一样的,但第二种方法更加巧妙,且快慢指针可以处理其他很多问题。
// 暴力求解
struct ListNode* middleNode(struct ListNode* head){
int num = 0;
struct ListNode* test = head;
while(test!=NULL){
num++;
test = test->next;
}
for(int i=0;i<num/2;i++){
head = head->next;
}
return head;
}
// 快慢指针
struct ListNode* middleNode(struct ListNode* head){
struct ListNode* slow = head;
struct ListNode* fast = head;
while((fast != NULL)&&(fast->next != NULL)){
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
第一次没好好读题,做成了普通二叉树的解法,给出代码,蛮简单的,然后又改成二叉搜索树的代码。结果显示,性能还不如暴力解法。
int Tranverse(struct TreeNode* root,int low,int high){
if(root == NULL){
return 0;
}
int k = 0;
if(root->val >= low && root->val <= high){
k = root->val;
}
return k + Tranverse(root->left,low,high) + Tranverse(root->right,low,high);
}
int rangeSumBST(struct TreeNode* root, int low, int high){
int k = Tranverse(root,low,high);
return k;
}
int Tranverse(struct TreeNode* root,int low,int high){
if(root == NULL){
return 0;
}
// 进行三重选择判断
if(root->val < low){
return 0 + Tranverse(root->right,low,high);
}else if(root->val > high){
return 0 + Tranverse(root->left,low,high);
}
return root->val + Tranverse(root->left,low,high) + Tranverse(root->right,low,high);
}
int rangeSumBST(struct TreeNode* root,int low,int high){
int k = Tranverse(root,low,high);
return k;
}
这题思路就是将数组进行n次轮转,每次从后往前挪动一个元素,然后检查是否升序排列。
bool check(int* nums, int numsSize){
int i;
for(int j=0;j<numsSize;j++){
int num =0;
int k = nums[numsSize-1];
for(int m = numsSize-2;m>=0;m--){
nums[m+1] = nums[m];
}
nums[0] = k;
for(i=0;i<numsSize-1;i++){
if(nums[i]<=nums[i+1]){
num++;
}
}
if(num == numsSize-1){
return true;
}
}
return false;
}
第一次参加力扣周赛,肝了两题还都是暴力,害,事后来诸葛亮了。
int maximumScore(int a, int b, int c){
if(a+b<=c)
return a+b;
else if(a+c<=b)
return a+c;
else if(b+c<=a)
return b+c;
return (a+b+c)/2;
}