leecode,rt_phm更新更新
This commit is contained in:
parent
00f5d9ebd1
commit
67bcb4b0bc
|
|
@ -0,0 +1,12 @@
|
|||
package com.markilue.leecode.hot100.interviewHot.singlestack;
|
||||
|
||||
/**
|
||||
*@BelongsProject: Leecode
|
||||
*@BelongsPackage: com.markilue.leecode.hot100.interviewHot.singlestack
|
||||
*@Author: markilue
|
||||
*@CreateTime: 2023-05-25 11:29
|
||||
*@Description: TODO 力扣239 滑动窗口最大值
|
||||
*@Version: 1.0
|
||||
*/
|
||||
public class LC_239_MaxSlidingWindow {
|
||||
}
|
||||
|
|
@ -13,7 +13,7 @@ import java.util.LinkedList;
|
|||
*@Description: TODO 力扣503 下一个更大元素II
|
||||
*@Version: 1.0
|
||||
*/
|
||||
public class T503_NextGreaterElements {
|
||||
public class LC_503_NextGreaterElements {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package com.markilue.leecode.hot100.interviewHot.speical;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
*@BelongsProject: Leecode
|
||||
*@BelongsPackage: com.markilue.leecode.hot100.second
|
||||
*@Author: markilue
|
||||
*@CreateTime: 2023-05-25 10:39
|
||||
*@Description: TODO 力扣238 除自身以外数组的乘积
|
||||
*@Version: 1.0
|
||||
*/
|
||||
public class T71_238_ProductExceptSelf {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
int[] nums = {1, 2, 3, 4};
|
||||
System.out.println(Arrays.toString(productExceptSelf(nums)));
|
||||
}
|
||||
|
||||
//思路:考虑分别使用一个left和right记录这个数左边数的乘积和右边数的乘积,最后计算总和
|
||||
//其实本题的矛盾点就在于:如果不想要当前,就会损失前面的或者后面的,就会瞻前顾后,遍历两次即可
|
||||
public int[] productExceptSelf(int[] nums) {
|
||||
int[] left = new int[nums.length];
|
||||
int[] right = new int[nums.length];
|
||||
left[0] = 1;
|
||||
right[nums.length - 1] = 1;
|
||||
for (int i = 1; i < nums.length; i++) {
|
||||
left[i] = left[i - 1] * nums[i - 1];
|
||||
}
|
||||
for (int i = nums.length - 2; i >= 0; i--) {
|
||||
right[i] = right[i + 1] * nums[i + 1];
|
||||
}
|
||||
|
||||
for (int i = 0; i < left.length; i++) {
|
||||
left[i] *= right[i];
|
||||
}
|
||||
return left;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -13,18 +13,18 @@ import org.junit.Test;
|
|||
public class T67_221_MaximalSquare {
|
||||
|
||||
@Test
|
||||
public void test(){
|
||||
public void test() {
|
||||
char[][] matrix = {
|
||||
{'1', '0', '1', '0', '0'},
|
||||
{'1', '0', '1', '1', '1'},
|
||||
{'1', '1', '1', '1', '1'},
|
||||
{'1', '0', '0', '1', '0'}
|
||||
};
|
||||
System.out.println(maximalSquare(matrix));
|
||||
System.out.println(maximalSquare1(matrix));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test1(){
|
||||
public void test1() {
|
||||
char[][] matrix = {
|
||||
{'1', '1'},
|
||||
{'1', '1'}
|
||||
|
|
@ -33,7 +33,7 @@ public class T67_221_MaximalSquare {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void test2(){
|
||||
public void test2() {
|
||||
char[][] matrix = {
|
||||
{'1', '0', '1', '0'},
|
||||
{'1', '0', '1', '1'},
|
||||
|
|
@ -67,7 +67,7 @@ public class T67_221_MaximalSquare {
|
|||
for (int i = 1; i < m; i++) {
|
||||
for (int j = 1; j < n; j++) {
|
||||
if (matrix[i][j] == '1') {
|
||||
dp[i][j] = Math.min(Math.min(dp[i - 1][j], dp[i][j - 1]),dp[i-1][j-1]) + 1;
|
||||
dp[i][j] = Math.min(Math.min(dp[i - 1][j], dp[i][j - 1]), dp[i - 1][j - 1]) + 1;
|
||||
result = Math.max(result, dp[i][j] * dp[i][j]);
|
||||
}
|
||||
}
|
||||
|
|
@ -76,4 +76,28 @@ public class T67_221_MaximalSquare {
|
|||
return result;
|
||||
|
||||
}
|
||||
|
||||
public int maximalSquare1(char[][] matrix) {
|
||||
int m = matrix.length;
|
||||
int n = matrix[0].length;
|
||||
int[][] dp = new int[m][n];
|
||||
int result = 0;
|
||||
|
||||
for (int i = 0; i < m; i++) {
|
||||
for (int j = 0; j < n; j++) {
|
||||
if (matrix[i][j] == '1') {
|
||||
if (i < 1 || j < 1) {
|
||||
dp[i][j] = 1;//因为第一层最多只有1
|
||||
} else {
|
||||
dp[i][j] = Math.min(Math.min(dp[i - 1][j], dp[i][j - 1]), dp[i - 1][j - 1]) + 1;//值得注意的是添加了dp[i-1][j-1]
|
||||
//因为正方形需要全是1,而对角为0的情况可能可能会计算出同样的结果
|
||||
}
|
||||
result = Math.max(result, dp[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result * result;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,48 @@
|
|||
package com.markilue.leecode.hot100.second;
|
||||
|
||||
import com.markilue.leecode.tree.TreeNode;
|
||||
|
||||
/**
|
||||
*@BelongsProject: Leecode
|
||||
*@BelongsPackage: com.markilue.leecode.hot100.second
|
||||
*@Author: markilue
|
||||
*@CreateTime: 2023-05-25 10:31
|
||||
*@Description: TODO 力扣236 二叉树的最近公共祖先
|
||||
*@Version: 1.0
|
||||
*/
|
||||
public class T70_236_LowestCommonAncestor {
|
||||
|
||||
//思路:先遍历到谁,谁就一定是最大的,其他的可能在子树上;或者在另一个树上;两者返回值都可以确定
|
||||
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
|
||||
if (root == null) {
|
||||
return root;
|
||||
} else if (root == p) {
|
||||
return p;
|
||||
} else if (root == q) {
|
||||
return q;
|
||||
}
|
||||
|
||||
//全都没碰到:在当前节点的子树上
|
||||
TreeNode left = lowestCommonAncestor(root.left, p, q);
|
||||
TreeNode right = lowestCommonAncestor(root.right, p, q);
|
||||
if (left != null && right != null) {
|
||||
return root;
|
||||
}else if(left==null){
|
||||
return right;
|
||||
}else {
|
||||
return left;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//优秀写法
|
||||
public TreeNode lowestCommonAncestor1(TreeNode root, TreeNode p, TreeNode q) {
|
||||
if (root == null || root == p || root == q) return root;
|
||||
TreeNode left = lowestCommonAncestor(root.left, p, q);
|
||||
TreeNode right = lowestCommonAncestor(root.right, p, q);
|
||||
if (left != null && right != null) {return root;}
|
||||
return left != null ? left : right;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package com.markilue.leecode.hot100.second;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
*@BelongsProject: Leecode
|
||||
*@BelongsPackage: com.markilue.leecode.hot100.second
|
||||
*@Author: markilue
|
||||
*@CreateTime: 2023-05-25 10:39
|
||||
*@Description: TODO 力扣238 除自身以外数组的乘积
|
||||
*@Version: 1.0
|
||||
*/
|
||||
public class T71_238_ProductExceptSelf {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
int[] nums = {1, 2, 3, 4};
|
||||
System.out.println(Arrays.toString(productExceptSelf(nums)));
|
||||
}
|
||||
|
||||
//思路:考虑分别使用一个left和right记录这个数左边数的乘积和右边数的乘积,最后计算总和
|
||||
//其实本题的矛盾点就在于:如果不想要当前,就会损失前面的或者后面的,就会瞻前顾后,遍历两次即可
|
||||
public int[] productExceptSelf(int[] nums) {
|
||||
int[] left = new int[nums.length];
|
||||
int[] right = new int[nums.length];
|
||||
left[0] = 1;
|
||||
right[nums.length - 1] = 1;
|
||||
for (int i = 1; i < nums.length; i++) {
|
||||
left[i] = left[i - 1] * nums[i - 1];
|
||||
}
|
||||
for (int i = nums.length - 2; i >= 0; i--) {
|
||||
right[i] = right[i + 1] * nums[i + 1];
|
||||
}
|
||||
|
||||
for (int i = 0; i < left.length; i++) {
|
||||
left[i] *= right[i];
|
||||
}
|
||||
return left;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
package com.markilue.leecode.hot100.second;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
*@BelongsProject: Leecode
|
||||
*@BelongsPackage: com.markilue.leecode.hot100.second
|
||||
*@Author: markilue
|
||||
*@CreateTime: 2023-05-25 10:56
|
||||
*@Description: TODO 力扣239 滑动窗口最大值
|
||||
*@Version: 1.0
|
||||
*/
|
||||
public class T72_239_MaxSlidingWindow {
|
||||
|
||||
@Test
|
||||
public void test(){
|
||||
int[] nums = {1, 3, -1, -3, 5, 3, 6, 7};
|
||||
int k = 3;
|
||||
System.out.println(Arrays.toString(maxSlidingWindow(nums,k)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test1(){
|
||||
int[] nums = {1,-1};
|
||||
int k = 1;
|
||||
System.out.println(Arrays.toString(maxSlidingWindow(nums,k)));
|
||||
}
|
||||
|
||||
//使用一个单调栈进行记录:定期排除过期元素
|
||||
public int[] maxSlidingWindow(int[] nums, int k) {
|
||||
ArrayDeque<int[]> stack = new ArrayDeque<>();//[num,index]
|
||||
int[] result = new int[nums.length - k + 1];
|
||||
|
||||
//先入栈前k个,确定result的第一个位置,以后每移动一位,result也赋值一位
|
||||
for (int i = 0; i < k; i++) {
|
||||
result[0] = Math.max(result[0], nums[i]);
|
||||
while (!stack.isEmpty() && stack.peek()[0] < nums[i]) {
|
||||
//在他前面,还比他小,那么一定不用记录了
|
||||
stack.pop();
|
||||
}
|
||||
stack.addFirst(new int[]{nums[i], i});
|
||||
}
|
||||
|
||||
for (int i = k; i < nums.length; i++) {
|
||||
//先清理掉尾部过期元素
|
||||
while (!stack.isEmpty() && (i - stack.peekLast()[1]) >= k) {
|
||||
//超过窗口了
|
||||
stack.pollLast();
|
||||
}
|
||||
//将当前元素记录在stack中
|
||||
while (!stack.isEmpty() && stack.peek()[0] < nums[i]) {
|
||||
//在他前面,还比他小,那么一定不用记录了
|
||||
stack.pop();
|
||||
}
|
||||
stack.addFirst(new int[]{nums[i], i});
|
||||
result[i - k + 1] = stack.peekLast()[0];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package com.markilue.leecode.hot100.second;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
*@BelongsProject: Leecode
|
||||
*@BelongsPackage: com.markilue.leecode.hot100.second
|
||||
*@Author: markilue
|
||||
*@CreateTime: 2023-05-25 11:31
|
||||
*@Description: TODO 力扣240 搜索二维矩阵II
|
||||
*@Version: 1.0
|
||||
*/
|
||||
public class T73_240_SearchMatrix {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
int[][] nums = {{1, 1}};
|
||||
System.out.println(searchMatrix(nums, 0));
|
||||
}
|
||||
|
||||
|
||||
//从左上角开始遍历:那么满足:target比当前值大,则向下;反之则向左
|
||||
public boolean searchMatrix(int[][] matrix, int target) {
|
||||
//左上角第一个数
|
||||
int nowI = 0;
|
||||
int nowJ = matrix[0].length - 1;
|
||||
|
||||
while (nowI < matrix.length && nowJ >= 0) {
|
||||
if (matrix[nowI][nowJ] == target) {
|
||||
return true;
|
||||
} else if (matrix[nowI][nowJ] < target) {
|
||||
nowI++;
|
||||
} else {
|
||||
nowJ--;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
package com.markilue.leecode.hot100.second;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
*@BelongsProject: Leecode
|
||||
*@BelongsPackage: com.markilue.leecode.hot100.second
|
||||
*@Author: markilue
|
||||
*@CreateTime: 2023-05-25 11:42
|
||||
*@Description: TODO 力扣279 完全平方数
|
||||
*@Version: 1.0
|
||||
*/
|
||||
public class T74_279_NumSquares {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
System.out.println(numSquares(12));
|
||||
}
|
||||
|
||||
public int numSquares(int n) {
|
||||
if (n < 1) return 0;
|
||||
int[] dp = new int[n + 1];
|
||||
dp[1] = 1;
|
||||
for (int i = 2; i < dp.length; i++) {
|
||||
dp[i] = i;//最多i个
|
||||
for (int j = 1; j <= Math.sqrt(i); j++) {
|
||||
dp[i] = Math.min(dp[i], dp[i - j * j] + 1);
|
||||
}
|
||||
}
|
||||
return dp[n];
|
||||
}
|
||||
}
|
||||
|
|
@ -30,6 +30,7 @@
|
|||
目前,有四种类型的变换可用:
|
||||
离散傅里叶变换(DFT)、离散余弦变换(DCT)、离散正弦变换(DST)和离散哈特利变换(DHT)-->
|
||||
<!--使用教程:http://wendykierp.github.io/JTransforms/apidocs/-->
|
||||
<!--经过测试,结果暂时不对-->
|
||||
<dependency>
|
||||
<groupId>com.github.wendykierp</groupId>
|
||||
<artifactId>JTransforms</artifactId>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
package com.cqu.algorithm.fft;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*@BelongsProject: phm_parent
|
||||
*@BelongsPackage: com.cqu.algorithm.fft
|
||||
*@Author: markilue
|
||||
*@CreateTime: 2023-05-24 15:24
|
||||
*@Description: TODO 构建Complex数组
|
||||
*@Version: 1.0
|
||||
*/
|
||||
public class BulidComplex {
|
||||
|
||||
public static Complex[] build(List<Double> raw) {
|
||||
Complex[] complexes = new Complex[raw.size()];
|
||||
for (int i = 0; i < complexes.length; i++) {
|
||||
complexes[i] = new Complex(raw.get(i));
|
||||
}
|
||||
return complexes;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
package com.cqu.algorithm.fft;
|
||||
|
||||
public class Complex {
|
||||
//复数类,实现复数的加减乘除以及重写toString方法
|
||||
private double real;
|
||||
private double image;
|
||||
|
||||
public Complex() {
|
||||
this(0,0);
|
||||
}
|
||||
|
||||
public Complex (double real) {
|
||||
this(real,0);
|
||||
}
|
||||
|
||||
public Complex(double real,double image) {
|
||||
this.real = real;
|
||||
this.image = image;
|
||||
}
|
||||
|
||||
public Complex plus(Complex complex) {
|
||||
double real2 = complex.getReal();
|
||||
double image2 = complex.getImage();
|
||||
double newReal =real + real2;
|
||||
double newImage =image + image2;
|
||||
return new Complex(newReal,newImage);
|
||||
}
|
||||
|
||||
public Complex minus(Complex complex) {
|
||||
double real2 = complex.getReal();
|
||||
double image2 = complex.getImage();
|
||||
double newReal =real - real2;
|
||||
double newImage =image - image2;
|
||||
return new Complex(newReal,newImage);
|
||||
}
|
||||
|
||||
public Complex multiply(Complex complex) {
|
||||
double real2 = complex.getReal();
|
||||
double image2 = complex.getImage();
|
||||
double newReal = real * real2 - image * image2;
|
||||
double newImage = image * real2 + real * image2;
|
||||
return new Complex(newReal,newImage);
|
||||
}
|
||||
|
||||
public Complex divide(Complex complex) {
|
||||
double real2 = complex.getReal();
|
||||
double image2 = complex.getImage();
|
||||
double newReal = (real*real2 + image*image2)/(real2*real2 + image2*image2);
|
||||
double newImage = (image*real2 - real*image2)/(real2*real2 + image2*image2);
|
||||
return new Complex(newReal,newImage);
|
||||
}
|
||||
|
||||
//计算真实大小的时部和虚部
|
||||
public Complex divide(int dim) {
|
||||
real = real * 2 / dim;
|
||||
image = image * 2 / dim;
|
||||
return this;
|
||||
}
|
||||
|
||||
//计算振幅
|
||||
public double getAmplitude() {
|
||||
return Math.sqrt(real * real + image * image);
|
||||
}
|
||||
|
||||
public double getReal() {
|
||||
return real;
|
||||
}
|
||||
public void setReal(double real) {
|
||||
this.real = real;
|
||||
}
|
||||
public double getImage() {
|
||||
return image;
|
||||
}
|
||||
public void setImage(double image) {
|
||||
this.image = image;
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "real=" + real + ", image=" + image;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package com.cqu.algorithm.fft;
|
||||
|
||||
|
||||
/**
|
||||
*@BelongsProject: phm_parent
|
||||
*@BelongsPackage: com.cqu.algorithm.fft
|
||||
*@Author: markilue
|
||||
*@CreateTime: 2023-05-24 15:24
|
||||
*@Description: TODO DFT算法的实现类
|
||||
*@Version: 1.0
|
||||
*/
|
||||
public class DFT {
|
||||
//DFT计算
|
||||
public static Complex[] dft(Complex[] x,int N) {
|
||||
|
||||
if(N == 1 || x.length == 1) {
|
||||
return x;
|
||||
}
|
||||
Complex result[] = new Complex[N];
|
||||
for(int k = 0; k < N; k++) {
|
||||
result[k] = new Complex();
|
||||
for(int n = 0; n<N; n++) {
|
||||
double W = -2*n*k*Math.PI/N;
|
||||
Complex c = new Complex(Math.cos(W),Math.sin(W));
|
||||
result[k] = result[k].plus(x[n].multiply(c));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,25 +1,148 @@
|
|||
package com.cqu.algorithm.fft;
|
||||
|
||||
import org.jtransforms.fft.BenchmarkDoubleFFT;
|
||||
import org.jtransforms.fft.BenchmarkFloatFFT;
|
||||
import org.jtransforms.fft.DoubleFFT_1D;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
*@BelongsProject: phm_parent
|
||||
*@BelongsPackage: com.cqu.algorithm.fft
|
||||
*@Author: markilue
|
||||
*@CreateTime: 2023-05-23 20:19
|
||||
*@Description: TODO FFT类
|
||||
*@CreateTime: 2023-05-24 15:24
|
||||
*@Description: TODO FFT算法的实现类
|
||||
*@Version: 1.0
|
||||
*/
|
||||
public class FFT {
|
||||
public static Complex[] fft(Complex[] x,int N) {
|
||||
//定义式计算FFT(方法一)
|
||||
if(N == 1 ) {
|
||||
return x;
|
||||
}
|
||||
// 如果信号数为奇数,使用dft计算
|
||||
if(N % 2 != 0) {
|
||||
return DFT.dft(x, N);
|
||||
}
|
||||
// 提取下标为偶数的原始信号值进行递归fft计算
|
||||
Complex[] even = new Complex[N / 2];
|
||||
for (int k = 0; k < even.length; k++) {
|
||||
even[k] = x[2 * k];
|
||||
}
|
||||
Complex[] evenValue = FFT.fft(even, even.length);
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
|
||||
new DoubleFFT_1D(10).complexForward(new double[10]);
|
||||
// 提取下标为奇数的原始信号值进行fft计算
|
||||
// 节约内存
|
||||
Complex[] odd = even;
|
||||
for (int k = 0; k < odd.length; k++) {
|
||||
odd[k] = x[2 * k + 1];
|
||||
}
|
||||
Complex[] oddValue = FFT.fft(odd,odd.length);
|
||||
// 偶数+奇数
|
||||
Complex[] result = new Complex[N];
|
||||
for (int k = 0; k < N / 2; k++) {
|
||||
double W = -2*k*Math.PI/N;
|
||||
Complex m = new Complex(Math.cos(W), Math.sin(W));
|
||||
result[k] = evenValue[k].plus(m.multiply(oddValue[k]));
|
||||
result[k + N / 2] = evenValue[k].minus(m.multiply(oddValue[k]));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void reverse(Complex[] A,int N) {
|
||||
//倒叙前N个数据
|
||||
int LH = N/2;
|
||||
int J = LH;
|
||||
int N1 = N-2;
|
||||
for(int I = 1;I <= N1; I++) {
|
||||
if(!(I >=J)) {
|
||||
Complex T = A[I];
|
||||
A[I] = A[J];
|
||||
A[J] = T;
|
||||
}
|
||||
int K = LH;
|
||||
while(!(J < K)) {
|
||||
J = J - K;
|
||||
K = K/2;
|
||||
}
|
||||
J += K;
|
||||
|
||||
}
|
||||
// return null;
|
||||
}
|
||||
|
||||
//对复数数组倒叙
|
||||
public static void reverse(Complex[] A) {
|
||||
int N = A.length;
|
||||
int LH = N/2;
|
||||
int J = LH;
|
||||
int N1 = N-2;
|
||||
for(int I = 1;I <= N1; I++) {
|
||||
if(!(I >=J)) {
|
||||
Complex T = A[I];
|
||||
A[I] = A[J];
|
||||
A[J] = T;
|
||||
}
|
||||
int K = LH;
|
||||
while(!(J < K)) {
|
||||
J = J - K;
|
||||
K = K/2;
|
||||
}
|
||||
J += K;
|
||||
|
||||
}
|
||||
// return null;
|
||||
}
|
||||
public static Complex[] myFFT(Complex[] A,int N) {
|
||||
//FFT计算(方法二)推荐这一种,错误小
|
||||
int M = returnM(N);
|
||||
Complex[] x = new Complex[N];
|
||||
System.arraycopy(A, 0, x, 0, N);
|
||||
reverse(x);
|
||||
for(int L = 1;L <= M;L++) {
|
||||
int B = (int)Math.pow(2, L-1);
|
||||
for(int J = 0;J <= B-1;J++) {
|
||||
int P = (int)Math.pow(2, M-L)*J;
|
||||
for(int k = J;k <= N-1;k += Math.pow(2, L)) {
|
||||
double W = -2*Math.PI*P/N;
|
||||
Complex c = x[k+B].multiply(new Complex(Math.cos(W),Math.sin(W)));
|
||||
Complex T = x[k].plus(c);
|
||||
x[k+B] = x[k].minus(c);
|
||||
x[k] = T;
|
||||
}
|
||||
}
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
public static Complex[] myFFT(Complex[] A,int offset,int N) {
|
||||
//FFT计算,计算从offset开始的N条数据
|
||||
int M = returnM(N);
|
||||
Complex[] x = new Complex[N];
|
||||
System.arraycopy(A, offset, x, 0, N);
|
||||
reverse(x);
|
||||
for(int L = 1;L <= M;L++) {
|
||||
int B = (int)Math.pow(2, L-1);
|
||||
for(int J = 0;J <= B-1;J++) {
|
||||
int P = (int)Math.pow(2, M-L)*J;
|
||||
for(int k = J;k <= N-1;k += Math.pow(2, L)) {
|
||||
double W = -2*Math.PI*P/N;
|
||||
Complex c = x[k+B].multiply(new Complex(Math.cos(W),Math.sin(W)));
|
||||
Complex T = x[k].plus(c);
|
||||
x[k+B] = x[k].minus(c);
|
||||
x[k] = T;
|
||||
}
|
||||
}
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
//返回一个数是2的几次幂
|
||||
public static int returnM(int N) {
|
||||
// int N = x.length;
|
||||
if((N&(N-1))!=0) {
|
||||
throw new RuntimeException("非2的整数幂");
|
||||
}
|
||||
int M=0;
|
||||
while((N = N / 2) != 0) {
|
||||
M++;
|
||||
}
|
||||
return M;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,99 @@
|
|||
package com.cqu.algorithm.fft;
|
||||
|
||||
import javax.print.DocFlavor;
|
||||
|
||||
/**
|
||||
*@BelongsProject: phm_parent
|
||||
*@BelongsPackage: com.cqu.algorithm.fft
|
||||
*@Author: markilue
|
||||
*@CreateTime: 2023-05-24 15:24
|
||||
*@Description:
|
||||
* TODO 每一个点的复数类;real表示实数;image表示虚数
|
||||
* 使用函数式编程接口:加减乘除都改变自身
|
||||
*@Version: 1.0
|
||||
*/
|
||||
public class MutableComplex {
|
||||
//复数类,实现复数的加减乘除以及重写toString方法
|
||||
private double real;
|
||||
private double image;
|
||||
|
||||
public MutableComplex() {
|
||||
this(0, 0);
|
||||
}
|
||||
|
||||
public MutableComplex(double real) {
|
||||
this(real, 0);
|
||||
}
|
||||
|
||||
public MutableComplex(double real, double image) {
|
||||
this.real = real;
|
||||
this.image = image;
|
||||
}
|
||||
|
||||
public MutableComplex plus(MutableComplex complex) {
|
||||
double real2 = complex.getReal();
|
||||
double image2 = complex.getImage();
|
||||
real = real + real2;
|
||||
image = image + image2;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MutableComplex minus(MutableComplex complex) {
|
||||
double real2 = complex.getReal();
|
||||
double image2 = complex.getImage();
|
||||
real = real - real2;
|
||||
image = image - image2;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MutableComplex multiply(MutableComplex complex) {
|
||||
double real2 = complex.getReal();
|
||||
double image2 = complex.getImage();
|
||||
real = real * real2 - image * image2;
|
||||
image = image * real2 + real * image2;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MutableComplex divide(MutableComplex complex) {
|
||||
double real2 = complex.getReal();
|
||||
double image2 = complex.getImage();
|
||||
real = (real * real2 + image * image2) / (real2 * real2 + image2 * image2);
|
||||
image = (image * real2 - real * image2) / (real2 * real2 + image2 * image2);
|
||||
return this;
|
||||
}
|
||||
|
||||
//计算真实大小的时部和虚部
|
||||
public MutableComplex divide(int dim) {
|
||||
real = real * 2 / dim;
|
||||
image = image * 2 / dim;
|
||||
return this;
|
||||
}
|
||||
|
||||
public double getReal() {
|
||||
return real;
|
||||
}
|
||||
|
||||
public void setReal(double real) {
|
||||
this.real = real;
|
||||
}
|
||||
|
||||
public double getImage() {
|
||||
return image;
|
||||
}
|
||||
|
||||
public void setImage(double image) {
|
||||
this.image = image;
|
||||
}
|
||||
|
||||
//计算振幅
|
||||
public double getAmplitude() {
|
||||
return Math.sqrt(real * real + image * image);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "real=" + real + ", image=" + image;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package com.cqu.algorithm.fft;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 测试
|
||||
*/
|
||||
public class TestComplex {
|
||||
//测试复数运算
|
||||
public static void main(String[] args) {
|
||||
Complex complex1 = new Complex(5);
|
||||
Complex complex2 = new Complex(4);
|
||||
System.out.println(complex1.multiply(complex2));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
package com.cqu.algorithm.fft;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* 测试FFT
|
||||
*/
|
||||
public class TestFFT {
|
||||
//测试DFT、FFT运算
|
||||
public static void main(String[] args) {
|
||||
// TODO Auto-generated method stub
|
||||
// test1();
|
||||
test3();
|
||||
}
|
||||
public static void test1() {
|
||||
Complex[] x = new Complex[5];
|
||||
x[0] = new Complex(4);
|
||||
x[1] = new Complex(3);
|
||||
x[2] = new Complex(2);
|
||||
x[3] = new Complex(1);
|
||||
x[4] = new Complex(0);
|
||||
for(Complex a:x) {
|
||||
System.out.println(a);
|
||||
}
|
||||
Complex[] x1 = DFT.dft(x, 5);
|
||||
for(Complex a:x1) {
|
||||
System.out.println(a);
|
||||
}
|
||||
}
|
||||
public static void test2() {
|
||||
Complex[] x = new Complex[8];
|
||||
for(int i = 0;i < x.length;i++) {
|
||||
x[i] = new Complex(i);
|
||||
}
|
||||
for(Complex a:x) {
|
||||
System.out.println(a);
|
||||
}
|
||||
Complex[] x1 = DFT.dft(x, 8);
|
||||
Complex[] x2 = FFT.fft(x, 8);
|
||||
Complex[] x3 = FFT.myFFT(x, 8);
|
||||
|
||||
for (int i = 0; i < x3.length; i++) {
|
||||
System.out.println(x1[i] + "/" + x2[i] + "/" + x3[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public static void test3() {
|
||||
|
||||
Complex[] x = BulidComplex.build(Arrays.asList(-0.029078494757,
|
||||
-0.33095228672,
|
||||
-0.12124221772,
|
||||
0.553512275219,
|
||||
-0.158036053181,
|
||||
0.268739402294,
|
||||
-0.638222515583,
|
||||
0.233140587807,
|
||||
-0.173265621066,
|
||||
0.467218101025,
|
||||
-0.372010827065,
|
||||
-0.136630430818,
|
||||
0.343256533146,
|
||||
0.008932195604));
|
||||
for(Complex a:x) {
|
||||
System.out.println(a);
|
||||
}
|
||||
Complex[] x1 = DFT.dft(x, 14);
|
||||
Complex[] x2 = FFT.fft(x, 14);
|
||||
// Complex[] x3 = FFT.myFFT(x, 14);
|
||||
|
||||
for (int i = 0; i < x2.length; i++) {
|
||||
System.out.println(x1[i] + "/" + x2[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -29,6 +29,7 @@ public abstract class BaseStreamApp {
|
|||
env.setRestartStrategy(RestartStrategies.fixedDelayRestart(3, 3000L));
|
||||
env.setStateBackend(new FsStateBackend(PHMConfig.RT_CHECKPOINT_LOCATION));
|
||||
System.setProperty("HADOOP_USER_NAME", PHMConfig.HADOOP_USER_NAME);
|
||||
System.setProperty("java.vm.name","Java HotSpot(TM) ");//使用的JDK版本
|
||||
//模板
|
||||
execute(env);
|
||||
env.execute();
|
||||
|
|
|
|||
|
|
@ -5,7 +5,9 @@ import com.alibaba.fastjson.JSONArray;
|
|||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.cqu.warehouse.realtime.app.base.BaseStreamApp;
|
||||
import com.cqu.warehouse.realtime.app.func.DataSamplingFunction;
|
||||
import com.cqu.warehouse.realtime.app.func.FFTSamplingFunction;
|
||||
import com.cqu.warehouse.realtime.utils.MyKafkaUtils;
|
||||
import jdk.nashorn.internal.ir.debug.ObjectSizeCalculator;
|
||||
import org.apache.flink.api.common.eventtime.SerializableTimestampAssigner;
|
||||
import org.apache.flink.api.common.eventtime.WatermarkStrategy;
|
||||
import org.apache.flink.api.common.functions.RichMapFunction;
|
||||
|
|
@ -200,6 +202,10 @@ public class WindCMSApp extends BaseStreamApp {
|
|||
@Override
|
||||
public void process(Tuple2<String, String> stringStringTuple2, ProcessWindowFunction<JSONObject, JSONObject, Tuple2<String, String>, TimeWindow>.Context context, Iterable<JSONObject> iterable, Collector<JSONObject> collector) throws Exception {
|
||||
JSONObject obj = null;
|
||||
//参考:https://zhuanlan.zhihu.com/p/534376156
|
||||
//经过测试:1000个点一发:iterable500M
|
||||
//10000个点一发:iterable370M
|
||||
System.out.println("iterable_data_size:" + ObjectSizeCalculator.getObjectSize(iterable));
|
||||
for (JSONObject jsonObject : iterable) {
|
||||
if (obj == null) {
|
||||
obj = jsonObject;
|
||||
|
|
@ -212,15 +218,40 @@ public class WindCMSApp extends BaseStreamApp {
|
|||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
//TODO 6.计算频谱 --不知道要计算多久,使用异步Stream进行计算
|
||||
SingleOutputStreamOperator<JSONObject> fftDS = AsyncDataStream.unorderedWait(
|
||||
mergeDS,
|
||||
new FFTSamplingFunction<JSONObject>() {
|
||||
@Override
|
||||
protected void setTransformData(JSONObject jsonObject, List<Double> fft) {
|
||||
jsonObject.put("x", fft);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Double> getTransformData(JSONObject jsonObject) {
|
||||
return jsonObject.getJSONArray("x").toJavaList(Double.class);
|
||||
}
|
||||
},
|
||||
60, TimeUnit.SECONDS
|
||||
);
|
||||
|
||||
//TODO 合并的结果大概有10000个数据:判断是否合理
|
||||
mergeDS.print(">>>");
|
||||
// fftDS.print(">>>");
|
||||
|
||||
//TODO 5.写回kafka
|
||||
mergeDS
|
||||
.map(jsonObject -> jsonObject.toJSONString())
|
||||
.addSink(
|
||||
MyKafkaUtils.getKafkaSink("dwm_wind_cms_10_downsampling")
|
||||
);
|
||||
// mergeDS
|
||||
// .map(jsonObject -> jsonObject.toJSONString())
|
||||
// .addSink(
|
||||
// MyKafkaUtils.getKafkaSink("dwm_wind_cms_10_downsampling")
|
||||
// );
|
||||
// fftDS
|
||||
// .map(jsonObject -> jsonObject.toJSONString())
|
||||
// .addSink(
|
||||
// MyKafkaUtils.getKafkaSink("dwm_wind_cms_10_frequency")
|
||||
// );
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
package com.cqu.warehouse.realtime.app.func;
|
||||
|
||||
import com.cqu.warehouse.realtime.utils.TransformUtils;
|
||||
import jdk.nashorn.internal.ir.debug.ObjectSizeCalculator;
|
||||
import org.apache.flink.streaming.api.functions.async.AsyncFunction;
|
||||
import org.apache.flink.streaming.api.functions.async.ResultFuture;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*@BelongsProject: phm_parent
|
||||
*@BelongsPackage: com.cqu.warehouse.realtime.app.func
|
||||
*@Author: markilue
|
||||
*@CreateTime: 2023-05-24 17:46
|
||||
*@Description: TODO 计算数据的FFT
|
||||
*@Version: 1.0
|
||||
*/
|
||||
public abstract class FFTSamplingFunction<T> implements AsyncFunction<T, T> {
|
||||
|
||||
|
||||
@Override
|
||||
public void asyncInvoke(T t, ResultFuture<T> resultFuture) throws Exception {
|
||||
List<Double> transformData = getTransformData(t);
|
||||
List<Double> fft = TransformUtils.fft(transformData);
|
||||
setTransformData(t,fft);
|
||||
System.out.println("fftDataSize:"+ObjectSizeCalculator.getObjectSize(t));
|
||||
resultFuture.complete(Collections.singleton(t));
|
||||
}
|
||||
|
||||
protected abstract void setTransformData(T t, List<Double> fft);
|
||||
|
||||
protected abstract List<Double> getTransformData(T t);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,8 +1,12 @@
|
|||
package com.cqu.warehouse.realtime.utils;
|
||||
|
||||
import com.cqu.algorithm.fft.Complex;
|
||||
import com.cqu.algorithm.fft.FFT;
|
||||
import org.jtransforms.dct.DoubleDCT_1D;
|
||||
import org.jtransforms.fft.DoubleFFT_1D;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
|
|
@ -16,21 +20,59 @@ import java.util.List;
|
|||
* 2)DCT
|
||||
* 3)DST
|
||||
* 4)DHT
|
||||
* 参考: <!--使用教程:http://wendykierp.github.io/JTransforms/apidocs/-->
|
||||
*@Version: 1.0
|
||||
*/
|
||||
public class TransformUtils {
|
||||
|
||||
public static void fft(double[] data) {
|
||||
new DoubleFFT_1D(data.length).complexForward(data);
|
||||
private static Complex[] buildComplex(double[] raw) {
|
||||
Complex[] complexes = new Complex[raw.length];
|
||||
for (int i = 0; i < complexes.length; i++) {
|
||||
complexes[i] = new Complex(raw[i]);
|
||||
}
|
||||
return complexes;
|
||||
}
|
||||
|
||||
public static double[] fft(List<Double> data) {
|
||||
double[] raw = new double[data.size()];
|
||||
for (int i = 0; i < raw.length; i++) {
|
||||
raw[i] = data.get(i);
|
||||
private static Complex[] buildComplex(List<Double> raw) {
|
||||
Complex[] complexes = new Complex[raw.size()];
|
||||
for (int i = 0; i < complexes.length; i++) {
|
||||
complexes[i] = new Complex(raw.get(i));
|
||||
}
|
||||
// fft(data.toArray(new Double[0]));
|
||||
fft(raw);
|
||||
return raw;
|
||||
return complexes;
|
||||
}
|
||||
|
||||
public static List<Double> fft(double[] data) {
|
||||
Complex[] raw = buildComplex(data);
|
||||
Complex[] fft = FFT.fft(raw, raw.length);
|
||||
return calculateAmplitude(fft);
|
||||
}
|
||||
|
||||
public static List<Double> fft(List<Double> data) {
|
||||
Complex[] raw = buildComplex(data);
|
||||
Complex[] fft = FFT.fft(raw, raw.length);
|
||||
return calculateAmplitude(fft);
|
||||
}
|
||||
|
||||
private static List<Double> calculateAmplitude(Complex[] fft) {
|
||||
List<Double> amplitudeList = new ArrayList<>();
|
||||
for (Complex complex : fft) {
|
||||
amplitudeList.add(complex.divide(fft.length).getAmplitude());
|
||||
}
|
||||
return amplitudeList;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
double[] array = {-0.029078494757, -0.33095228672, -0.12124221772, 0.553512275219, -0.158036053181,
|
||||
0.268739402294,
|
||||
-0.638222515583,
|
||||
0.233140587807,
|
||||
-0.173265621066,
|
||||
0.467218101025,
|
||||
-0.372010827065,
|
||||
-0.136630430818,
|
||||
0.343256533146,
|
||||
0.008932195604};
|
||||
List<Double> fft = fft(array);
|
||||
System.out.println(fft);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue