有营养的算法笔记(四)

有营养的算法笔记四)

    • 右移二叉树
    • 二进制取反
    • k进制下1的数量
    • 高尔夫球场

右移二叉树

1.对应OJ链接

右移二叉树

2.题目描述

有营养的算法笔记(四)_第1张图片

3.解题思路

按照题目的意思,如果我们将这颗二叉树的节点放到一个容器当中其实就是将这个容器里面的元素左移k元素然后再将上一层的父亲指针指向调整好的这一层,没一层都这么干。最后将根节点返回即可
有营养的算法笔记(四)_第2张图片
我们将这个每一层放到数组里面之后并且旋转之后,我们只需要将上一层的节点连好这一层就可以了。注意我们先把下一层旋转并且调整好了之后才旋转上一层。

4.对应代码

/**
 * struct TreeNode {
 *	int val;
 *	struct TreeNode *left;
 *	struct TreeNode *right;
 *	TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 * };
 */
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param root TreeNode类 
     * @param k int整型 
     * @return TreeNode类
     */
    TreeNode* cyclicShiftTree(TreeNode* root, int k) {
        // write code here
        if(root==nullptr){
            return nullptr;
        }
        queue<TreeNode*>q;
        //用来进行层序遍历
        vector<vector<TreeNode*>>levels;//用来保存每一层的节点
        q.push(root);
       
        while(!q.empty())
        {
            vector<TreeNode*>tmp;//用来保存这一层的节点
            int len=q.size();
            for(int i=0;i<len;i++)
            {
                auto node=q.front();
                q.pop();
                tmp.push_back(node);
                if(node==nullptr){
                    continue;
                }
                //注意空节点我们也需要将其放入到队列当中
                q.push(node->left);
                q.push(node->right);
            }
            levels.push_back(move(tmp));
            //收集好这一层的节点
        }
        //注意最后一层是空节点我们需要将其删除掉
        levels.pop_back();
        int N=levels.size();
        //第一层不用进行调整
        for(int i=N-1;i>=1;i--)
        {
            //拿出一层来进行调整
            auto&level=levels[i];
            RotateLk(level,k);
            //进行旋转
            int index=0;
            for(auto &node:levels[i-1])
            {
                if(node)
                {
                    node->left=level[index++];
                    node->right=level[index++];
                }
            }
            
        }
        return root;
    }
    //向左旋转K个
    void RotateLk(vector<TreeNode*>&nums,int k)
    {
        int N=nums.size();
        k%=N;
        reverse(nums.begin(),nums.begin()+N-k);
        reverse(nums.begin()+N-k,nums.end());
        reverse(nums.begin(),nums.end());
        
    }
};

二进制取反

1.对应OJ链接

二进制取反

2.题目描述
有营养的算法笔记(四)_第3张图片

3.解题思路

从左往右遍历找到第一个为0的点就停下来并且将其下标记录下来,然后从这个下标开始往后遍历遇到0就改成1直到遇到1就停止将字符串返回即可。太简单了水的我自己都受不了了。

4.对应代码

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param num string字符串 
     * @return string字符串
     */
    string maxLexicographical(string num) {
        // write code here
        int N=num.size();
        int index=-1;
        int i=0;
        while(i<N)
        {
            if(num[i]=='0'){
                index=i;
                break;
            }
            i++;
        }
        //字符串全是1
        if(index==-1){
            return num;
        }
        
        while(index<N){
            if(num[index]=='1'){
                break;
            }
            num[index++]='1';
        }
        return num;
    }
};

k进制下1的数量

1.对应OJ链接

K进制下1的数量

2.题目描述

有营养的算法笔记(四)_第4张图片

3.解题思路

本题的解题思路也比较的容易想到,题目说的是再k进制下求1到m的当中1的数量但是要求1的数量必须要大于等于n,要我们找到最小的m让1到m当中1的数量要比n要大。这一看就是明显的二分。首先如果n在k进制下的位数为len位,那门m不可能超过k^(len+1)。我们可以在1~这个范围内进行二分,先取中点假设为mid然后再判断1到mid当中1的数量是否要大于等于n如果是记录一下答案R=mid-1去左边二分否则去右边二分。思路很简单,最重要的是k进制下1到m的数量该如何求,这个如果不是很明白的老铁可以去看我以前的博客,再这里就不重复进行赘述。

4.对应代码

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param n int整型 
     * @param k int整型 
     * @return long长整型
     */
    typedef long long ll;
    long long minM(int n, int k) {
        // write code here
        ll L=1;
        int len=GetLen(n,k);
        ll R=power(k,len+1);
        ll ans=0;
        while(L<=R)
        {
            ll mid=L+(R-L)/2;
            if(GetOnes(mid,k)>=n){
                ans=mid;
                R=mid-1;
            }
            else
            {
                L=mid+1;
            }
        }
        return ans;
    }

       long  long power(long base, int power) {
		ll ans = 1;
		while (power != 0) {
			if ((power & 1) != 0) {
				ans *= base;
			}
			base *= base;
			power >>= 1;
		}
		return ans;
	}
    
    int GetLen(int num,int k)
    {
        int ans=0;
        while(num!=0)
        {
            num/=k;
            ans++;
        }
        return ans;
    }
    ll GetOnes(ll n,int k)
    {
        ll ans=0;
        ll i=1;
        ll tmp=n/i;
        while(tmp)
        {
            ans+=(tmp/k)*i;
            long long  cur=tmp%k;//看一下当前位
            if(cur>1){
                ans+=i;
            }
            else if(cur==1){
                ans+=n-tmp*i+1;
            }
            i*=k;
            tmp=n/i;
        }
        return ans;
    }
};

高尔夫球场

1.对应letecode链接
高尔夫球场

2.题目描述
有营养的算法笔记(四)_第5张图片

3.解题思路

本题的解题思路非常的简单,就是从一个点以最经济的方式走到哪里,如果不能走到哪里说明无法完成任务。而以最经济的方式走到某个位置我们需要使用宽度优先遍历来获取最优的方式走到某个点。下面我们来看看初始代码

class Solution {
  public:
    vector<vector<int>>dxy{{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
    int cutOffTree(vector<vector<int>>& forest) {
        int M = forest.size();
        int N = forest[0].size();
        vector<pair<int, int>>cells;
        for (int i = 0; i < M; i++) {
            for (int j = 0; j < N; j++) {
                if (forest[i][j] > 1) {//将树保存起来
                    cells.emplace_back(i, j);
                }
            }
        }
        auto cmp = [&](pair<int, int>& a, pair<int, int>& b) {
            return forest[a.first][a.second] < forest[b.first][b.second];
        };
        sort(cells.begin(), cells.end(), cmp);
        //按照点进行排序
        int lastR = 0;
        int lastC = 0;
        //上一个点的行和列
        int ans = 0;
        for (auto& cell : cells) {
            int MinStep = walkBest(forest, lastR, lastC, cell.first, cell.second);
            //到下一个点最优的步数
            if (MinStep == -1) {
                return -1;
            }
            ans += MinStep;
            lastR = cell.first;
            lastC = cell.second;
            forest[lastR][lastC] = 1;
        }
        return ans;


    }
    int walkBest(vector<vector<int>>& forest, int sx, int sy, int tx, int ty) {
        if (sx == tx && sy == ty) {
            return 0;
        }

        int row = forest.size();
        int col = forest[0].size();
        int step = 0;
        queue<vector<int>> qu;
        vector<vector<bool>> visited(row, vector<bool>(col, false));
        qu.push({sx, sy});
        visited[sx][sy] = true;
        while (!qu.empty()) {
            step++;
            int sz = qu.size();
            for (int i = 0; i < sz; ++i) {
                auto node = qu.front();
                qu.pop();
                for (int j = 0; j < 4; ++j) {
                    int nx = cx + dxy[j][0];
                    int ny = cy + dxy[j][1];
                    if (nx >= 0 && nx < row && ny >= 0 && ny < col && !visited[nx][ny] &&
                            forest[nx][ny] > 0) {

                        if (nx == tx && ny == ty) {
                            return step;
                        }
                        qu.push({nx, ny});
                        visited[nx][ny] = true;

                    }
                }
            }
        }
        return -1;
    }



};

你可能感兴趣的:(有营养的算法笔记,算法,leetcode,c++)