数据结构与算法---Pow(x, y)、圆圈中最后剩下的数字

本文探讨如何使用快速幂优化pow(x,n)计算,同时介绍了基于约瑟夫环问题的解决方案,展示了两种高效算法并应用于特定场景。

Pow(x, y)

50. Pow(x, y)

实现 pow(x, n) ,即计算 x 的 n 次幂函数。

示例 1:
输入: 2.00000, 10
输出: 1024.00000

示例 2:
输入: 2.10000, 3
输出: 9.26100

示例 3:
输入: 2.00000, -2
输出: 0.25000
解释: 2-2 = 1/22 = 1/4 = 0.25

说明:
-100.0 < x < 100.0
n 是 32 位有符号整数,其数值范围是 [−231, 231 − 1] 。


思路1:直接乘n次

第一步想到的就是,既然是幂,直接进行循环承即可

class Solution {
    public double myPow(double x, int n) {
        double result = 1;
        if(n == 0) return result;
        
        if(n > 0){
            while(n > 0){
                result = result * x;
                n--;
            }
            return result;
        }else{
            n = -n;
            while(n > 0){
                result = result * x;
                n--;
            }
            return 1.0/result;
        }
    }
}

无奈,超出了时间限制

在这里插入图片描述
上述代码可以简化下:

class Solution {
    public double myPow(double x, int n) {
        double result = 1.0;
        if(n == 0) return result;
        
        boolean isZhengShu = n > 0 ? true : false;
        n = isZhengShu ? n : -n;
        while(n > 0){
            result = result * x;
            n--;
        }
        return isZhengShu ? result : 1.0/result;
    }
}

思路2:快速幂

快速幂,其实是利用分治的思想
可以将时间复杂度降为O(logn)

快速幂,可以使用递归,也可以使用迭代
使用递归的空间复杂度为O(logn)
使用迭代的空间复杂度为O(1)

递归
class Solution {
    public double myPow(double x, int n) {
        if(n == 0) return 1;
        if(n == -1) return 1/x;
        //判断是否为奇数
        boolean odd = n % 2 == 0 ? false : true;
        double half = myPow(x, n >> 1);
        half *= half;
        return odd ? (half * x) : half;
    }
}

时间复杂度分析:
T(n) = T(n / 2) + O(1)
T(n) = O(logn);

注意
这道题涉及的知识点挺多,比较能看出一个人的水平

迭代

在这里插入图片描述
在这里插入图片描述

class Solution {
    public double myPow(double x, int n) {
        //是否为负数
        boolean neg = n < 0;
        long y = neg ? -((long)n) : n;

        double result = 1.0;

        while(y > 0){
            if((y & 1) == 1){
                //如果最后一个二进制位是1,就累乘上x
                result *= x;
            }
            x *= x;
            //舍弃掉最后一个二进制位
            y >>= 1;
        }
        return neg ? 1/result : result;
    }
}

看到一个哥们这么写:
在这里插入图片描述
真是一个小机灵鬼

试了下,好像被LeetCode禁止调用这个函数了

在这里插入图片描述


圆圈中最后剩下的数字

圆圈中最后剩下的数字

0,1,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字。求出这个圆圈里剩下的最后一个数字。

例如,0、1、2、3、4这5个数字组成一个圆圈,从数字0开始每次删除第3个数字,则删除的前4个数字依次是2、0、4、1,因此最后剩下的数字是3。

示例 1:

输入: n = 5, m = 3
输出: 3

示例 2:

输入: n = 10, m = 17
输出: 2

限制:

1 <= n <= 10^5
1 <= m <= 10^6

思路:公式

其实就是约瑟夫环问题,看谁活到最后

计算公式:
f(n, m) = (f(n - 1, m) + m) % n

递归
class Solution {
    public int lastRemaining(int n, int m) {
        if(n == 1) return 0;
        return (lastRemaining(n - 1, m) + m) % n;
    }
}
非递归

f(5, 3) = (f(4, 3) + 3) % 5;
f(4, 3) = (f(3, 3) + 3) % 4;
f(3, 3) = (f(2, 3) + 3) % 3;
f(2, 3) = (f(1, 3) + 3) % 2;
f(1, 3) = 0;
由上面公式推导出:

class Solution {
    public int lastRemaining(int n, int m) {
        int result = 0;
        for(int i = 2; i <= n; i++){
            result = (result + m) % i;
        }
        return result;
    }
}

其实也是根据公式得出来的,只是,不是直接递归调用公式

<think>嗯,用户现在想了解如何使用加速度传感器和C++实现动态手势识别算法。首先,我需要回顾之前的对话,看看有没有相关的信息可以引用。用户之前问过动态手势识别算法,我详细介绍了基于摄像头和深度学习的方案,包括MediaPipe、CNN-RNN模型等。但现在用户转向了加速度传感器和C++,所以需要调整思路。 用户提供的引用中,引用[1]提到了C/C++在嵌入式系统中的优势,特别是硬件接口编程,这可能和加速度传感器的数据采集有关。引用[3]提到了基于运动传感器的手势识别,但具体是摄像头,不过提到了预处理和模型的使用,可能有参考价值。用户明确要求加速度传感器和C++,所以需要结合这两点。 首先,我得考虑加速度传感器的工作原理。通常,加速度传感器提供三轴数据(X、Y、Z),动态手势会产生特定的时间序列模式,比如挥手、画圈等。识别这类手势的关键在于特征提取和分类算法。 接下来,需要设计流程。数据采集部分,C++如何读取传感器数据?可能需要用到特定的硬件接口,比如I2C或SPI协议。预处理阶段,可能需要滤波(如低通滤波去噪)、归一化处理。特征提取方面,时域特征(均值、方差、峰值)、频域特征(FFT)以及轨迹特征可能有用。分类算法的话,SVM、DTW或者简单的神经网络都是可能的选择。 代码示例方面,用户需要C++的示例。可能需要模拟数据采集的代码,比如读取传感器数据并存储为时间序列。预处理部分,展示如何应用移动平均滤波。特征提取的代码,比如计算均值、方差,或者FFT变换。分类部分,可以给出SVM或DTW的简单实现,或者调用现有库如OpenCV的ML模块。 同时,要考虑嵌入式系统的资源限制,可能需要在算法优化上下功夫,比如固定点运算、内存管理。性能优化方面,可以提到循环缓冲区、查表法等技巧。 用户可能还关心如何评估模型,比如交叉验证或实时测试。此外,实际应用中的问题,比如不同用户的动作差异、传感器噪声处理,也需要考虑。 需要确保回答结构清晰,分步骤讲解,并提供可运行的代码片段。同时,根据引用[1],强调C++在嵌入式中的优势,比如直接操作硬件、高效的内存管理,以及如何集成到小车控制系统中。 最后,生成相关问题,比如评估方法、优化策略、多传感器融合等,帮助用户进一步探索。</think>以下是基于加速度传感器和C++实现动态手势识别的技术方案及代码实现详解,结合嵌入式系统特性和传感器数据处理特点: --- ### 一、技术实现架构 #### 1. 硬件系统组成 ``` 加速度传感器(MPU6050) → 微控制器(STM32) → 手势识别算法 → 控制指令输出 ``` - **传感器选型**:MPU6050(6轴IMU,含3轴加速度+3轴陀螺仪),采样率≥50Hz[^1] - **通信接口**:通过I2C协议读取原始数据(C++直接操作寄存器) #### 2. 算法实现流程 ```mermaid graph TD A[数据采集] --> B[预处理] B --> C[特征提取] C --> D[模式识别] D --> E[分类输出] ``` --- ### 二、核心代码实现 #### 1. 加速度数据采集(C++嵌入式代码) ```cpp #include <Wire.h> #define MPU6050_ADDR 0x68 #define SMPLRT_DIV 0x19 #define ACCEL_CONFIG 0x1C #define ACCEL_XOUT_H 0x3B // 初始化传感器 void initMPU6050() { Wire.begin(); Wire.beginTransmission(MPU6050_ADDR); Wire.write(SMPLRT_DIV); Wire.write(0x07); // 设置采样率125Hz Wire.write(ACCEL_CONFIG); Wire.write(0x00); // ±2g量程 Wire.endTransmission(true); } // 读取三轴加速度数据 struct AccData { float x, y, z; }; AccData readAccelerometer() { Wire.beginTransmission(MPU6050_ADDR); Wire.write(ACCEL_XOUT_H); Wire.endTransmission(false); Wire.requestFrom(MPU6050_ADDR, 6, true); AccData data; data.x = (Wire.read() << 8 | Wire.read()) / 16384.0; // 转换为g值 data.y = (Wire.read() << 8 | Wire.read()) / 16384.0; data.z = (Wire.read() << 8 | Wire.read()) / 16384.0; return data; } ``` #### 2. 数据预处理(滑动窗口+滤波) ```cpp #include <queue> #include <array> const int WINDOW_SIZE = 30; // 对应0.6秒数据(50Hz采样) class DataBuffer { private: std::queue<std::array<float, 3>> buffer; public: void addSample(float x, float y, float z) { // 移动平均滤波 static float avg_x=0, avg_y=0, avg_z=0; avg_x = 0.9*avg_x + 0.1*x; avg_y = 0.9*avg_y + 0.1*y; avg_z = 0.9*avg_z + 0.1*z; buffer.push({avg_x, avg_y, avg_z}); if(buffer.size() > WINDOW_SIZE) buffer.pop(); } std::vector<std::array<float,3>> getWindow() { std::vector<std::array<float,3>> window; while(!buffer.empty()) { window.push_back(buffer.front()); buffer.pop(); } return window; } }; ``` #### 3. 特征提取(时域+频域特征) ```cpp #include <cmath> #include <vector> struct FeatureVector { float mean_x, mean_y, mean_z; float std_x, std_y, std_z; float energy_x, energy_y, energy_z; }; FeatureVector extractFeatures(const std::vector<std::array<float,3>>& window) { FeatureVector feat; // 计算均值 float sum_x=0, sum_y=0, sum_z=0; for(const auto& sample : window) { sum_x += sample[0]; sum_y += sample[1]; sum_z += sample[2]; } feat.mean_x = sum_x / window.size(); feat.mean_y = sum_y / window.size(); feat.mean_z = sum_z / window.size(); // 计算标准差 float var_x=0, var_y=0, var_z=0; for(const auto& sample : window) { var_x += pow(sample[0]-feat.mean_x, 2); var_y += pow(sample[1]-feat.mean_y, 2); var_z += pow(sample[2]-feat.mean_z, 2); } feat.std_x = sqrt(var_x/window.size()); feat.std_y = sqrt(var_y/window.size()); feat.std_z = sqrt(var_z/window.size()); // 计算能量(频域特征) for(const auto& sample : window) { feat.energy_x += pow(sample[0], 2); feat.energy_y += pow(sample[1], 2); feat.energy_z += pow(sample[2], 2); } return feat; } ``` #### 4. 手势分类(SVM示例) ```cpp #include <opencv2/ml.hpp> // 训练好的SVM模型(需提前离线训练) cv::Ptr<cv::ml::SVM> svm = cv::ml::SVM::load("gesture_svm.xml"); int classifyGesture(const FeatureVector& feat) { cv::Mat sample(1, 9, CV_32F); sample.at<float>(0) = feat.mean_x; sample.at<float>(1) = feat.mean_y; sample.at<float>(2) = feat.mean_z; sample.at<float>(3) = feat.std_x; sample.at<float>(4) = feat.std_y; sample.at<float>(5) = feat.std_z; sample.at<float>(6) = feat.energy_x; sample.at<float>(7) = feat.energy_y; sample.at<float>(8) = feat.energy_z; return static_cast<int>(svm->predict(sample)); } ``` --- ### 三、优化策略 1. **实时性优化**: - 使用固定点运算替代浮点运算 - 采用循环缓冲区减少内存拷贝 - 启用ARM Cortex-M系列的DSP指令集 2. **精度提升**: - 增加陀螺仪数据融合(四元数姿态解算) - 采用DTW(Dynamic Time Warping)算法处理时序变化 ```cpp // DTW距离计算伪代码 float dtwDistance(const std::vector<float>& seq1, const std::vector<float>& seq2) { int n = seq1.size(), m = seq2.size(); std::vector<std::vector<float>> dp(n+1, std::vector<float>(m+1, INFINITY)); dp[0][0] = 0; for(int i=1; i<=n; ++i) for(int j=1; j<=m; ++j) dp[i][j] = std::min({dp[i-1][j], dp[i][j-1], dp[i-1][j-1]}) + fabs(seq1[i-1]-seq2[j-1]); return dp[n][m]; } ``` 3. **节能策略**: - 动态调整采样率(静止时10Hz,检测到运动时切换至100Hz) - 采用事件驱动架构,只有特征超过阈值才唤醒主处理器 --- ### 四、典型手势定义示例 | 手势类型 | 加速度特征模式 | |---------|----------------| | 上挥 | Z轴正方向持续加速度变化 | | 画圆圈 | X/Y轴周期性正弦波动 | | 双击 | 短时间高能量脉冲峰 | | 左滑动 | X轴负方向持续变化+Y轴低方差 | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值