最近在项目中要仿支付宝做一个运动轨迹的曲线图。话不多说先上图

仿支付宝运动轨迹曲线图

需求 过去7天有动画、时间轴、阴影、点击时显示步数、横向轴有步数均值

我是通过自定义View实现这些需求的,绘制之前需要掌握自定义View的基本操作方法。

代码如下

import 你项目的包名import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.graphics.Point;
import android.graphics.Shader;
import android.graphics.SweepGradient;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;import com.zdkj.module_sport.R;
import com.zdkj.module_sport.view.activity.api.e.SpetEvent;import org.greenrobot.eventbus.EventBus;import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;/*** @author guoqiang* @date 2019/12/18.* description:1580321809@qq.com*/public class UshareChatView extends View {private Paint xianPaint;private Paint pointPaint;private Paint datelinePaint;private Paint circlePaint;private Paint textRulerPaint;private Paint textPointPaint;private Path linePath;private Path tablePath;private Path mFillPath = new Path();private int mWidth, mHeight;private List<DataBean> dataList = new ArrayList<>();private String[] xline = new String[7];private Point[] linePoints;private int stepStart;private int stepEnd;private int stepSpace;private int stepSpaceDefault = 43;private int stepSpaceDP = stepSpaceDefault;private int topSpace, bottomSpace;private int tablePadding;private int tablePaddingDP = 20;private int maxValue, minValue;private int rulerValueDefault = 5000;private int rulerValue = rulerValueDefault;private int rulerValuePadding;private int rulerValuePaddingDP = 8;private float heightPercent = 0.618f;private float lineWidthDP = 2f;private int pointColor = Color.parseColor("#5FB4F8");private float pointWidthDefault = 2f;private float pointWidthDP = pointWidthDefault;private int datelineColor = Color.parseColor("#BBBBBB");private float datelineWidthDefault = 0.5f;private float datelineWidthDP = 0.5f;//锚点宽度dpprivate int tableColor = Color.parseColor("#BBBBBB");private float tableWidthDP = 0.5f;private int rulerTextColor = tableColor;private float rulerTextSizeSP = 10f;private int pointTextColor = Color.parseColor("#009688");private float pointTextSizeSP = 10f;private boolean isShowTable = true;private boolean isBezierLine = true;private boolean isInitialized = false;private boolean isPlayAnim = true;private ValueAnimator valueAnimator;private float currentValue = 0f;private boolean isAnimating = false;private int endX;private int startX;private int index;public UshareChatView(Context context) {this(context, null);}public UshareChatView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public UshareChatView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);setupView();}private void setupView() {xianPaint = new Paint();xianPaint.setStyle(Paint.Style.STROKE);xianPaint.setAntiAlias(true);LinearGradient linearGradient = new LinearGradient(100, 100, 500, 500, Color.parseColor("#67C0F8"), Color.parseColor("#4487F6"), Shader.TileMode.CLAMP);int[] colorSweep = {Color.parseColor("#67C0F8"), Color.parseColor("#4487F6"), Color.parseColor("#67C0F8")};float[] position = {0f, 0.5f, 1f};Shader shader = new SweepGradient(getWidth() >> 1, getHeight() >> 1, colorSweep, position);xianPaint.setShader(shader);xianPaint.setShader(linearGradient);xianPaint.setStrokeWidth(dip2px(lineWidthDP));pointPaint = new Paint();pointPaint.setAntiAlias(true);pointPaint.setStyle(Paint.Style.STROKE);pointPaint.setColor(pointColor);pointPaint.setStrokeWidth(dip2px(pointWidthDP));datelinePaint = new Paint();datelinePaint.setAntiAlias(true);datelinePaint.setStyle(Paint.Style.STROKE);datelinePaint.setColor(datelineColor);datelinePaint.setStrokeWidth(dip2px(datelineWidthDP));circlePaint = new Paint();circlePaint.setAntiAlias(true);circlePaint.setStyle(Paint.Style.STROKE);circlePaint.setColor(tableColor);circlePaint.setStrokeWidth(dip2px(tableWidthDP));textRulerPaint = new Paint();textRulerPaint.setAntiAlias(true);textRulerPaint.setStyle(Paint.Style.FILL);textRulerPaint.setTextAlign(Paint.Align.CENTER);textRulerPaint.setColor(rulerTextColor);textRulerPaint.setTextSize(sp2px(rulerTextSizeSP));textPointPaint = new Paint();textPointPaint.setAntiAlias(true);textPointPaint.setStyle(Paint.Style.FILL);textPointPaint.setTextAlign(Paint.Align.CENTER);textPointPaint.setColor(pointTextColor);textPointPaint.setTextSize(sp2px(pointTextSizeSP));linePath = new Path();tablePath = new Path();resetParam();}private void initAnim() {valueAnimator = ValueAnimator.ofFloat(0f, 1f).setDuration(dataList.size() * 150);valueAnimator.setInterpolator(new AccelerateDecelerateInterpolator());valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {currentValue = (float) animation.getAnimatedValue();postInvalidate();}});valueAnimator.addListener(new AnimatorListenerAdapter() {@Overridepublic void onAnimationStart(Animator animation) {super.onAnimationStart(animation);currentValue = 0f;isAnimating = true;}@Overridepublic void onAnimationEnd(Animator animation) {super.onAnimationEnd(animation);currentValue = 1f;isAnimating = false;isPlayAnim = false;}});valueAnimator.setStartDelay(500);}private void resetParam() {linePath.reset();tablePath.reset();stepSpace = dip2px(stepSpaceDP);tablePadding = dip2px(tablePaddingDP);rulerValuePadding = dip2px(rulerValuePaddingDP);stepStart = tablePadding * (isShowTable ? 2 : 1);stepEnd = stepStart + stepSpace * (dataList.size() - 1);topSpace = bottomSpace = tablePadding;linePoints = new Point[7];initAnim();isInitialized = false;}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {int width = tablePadding + getTableEnd() + getPaddingLeft() + getPaddingRight();int heightMode = MeasureSpec.getMode(heightMeasureSpec);int height = MeasureSpec.getSize(heightMeasureSpec);if (MeasureSpec.EXACTLY == heightMode) {height = getPaddingTop() + getPaddingBottom() + height;}setMeasuredDimension(width, height);}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);mWidth = w;mHeight = h;}@Overrideprotected void onFinishInflate() {super.onFinishInflate();}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.drawColor(Color.TRANSPARENT);canvas.translate(0f, mHeight / 2f + (getViewDrawHeight() + topSpace + bottomSpace) / 2f);if (!isInitialized) {setupLine();}drawCircle(canvas);drawTable(canvas);drawLinePoints(canvas);}private void drawText(Canvas canvas, Paint textPaint, String text, float x, float y) {canvas.drawText(text, x, y, textPaint);}private void drawRulerYText(Canvas canvas, String text, float x, float y) {textRulerPaint.setTextAlign(Paint.Align.RIGHT);Paint.FontMetrics fontMetrics = textRulerPaint.getFontMetrics();float fontTotalHeight = fontMetrics.bottom - fontMetrics.top;float offsetY = fontTotalHeight / 2 - fontMetrics.bottom;float newY = y + offsetY;float newX = x - rulerValuePadding;drawText(canvas, textRulerPaint, text, newX, newY);}private void drawRulerXText(Canvas canvas, String text, float x, float y) {textRulerPaint.setTextAlign(Paint.Align.CENTER);Paint.FontMetrics fontMetrics = textRulerPaint.getFontMetrics();float fontTotalHeight = fontMetrics.bottom - fontMetrics.top;float offsetY = fontTotalHeight / 2 - fontMetrics.bottom;float newY = y + offsetY + rulerValuePadding;drawText(canvas, textRulerPaint, text, x, newY);}private void drawLinePointText(Canvas canvas, String text, float x, float y) {textPointPaint.setTextAlign(Paint.Align.CENTER);float newY = y - rulerValuePadding;drawText(canvas, textPointPaint, text, x, newY);}private int getTableStart() {return isShowTable ? stepStart + tablePadding : stepStart;}private int getTableEnd() {return isShowTable ? stepEnd + tablePadding : stepEnd;}private void drawCircle(Canvas canvas) {canvas.translate(0f, -dip2px(10));int tableEnd = getTableEnd();int rulerCount = maxValue / rulerValue;int rulerMaxCount = maxValue % rulerValue > 0 ? rulerCount + 1 : rulerCount;int rulerMax = rulerValue * rulerMaxCount + rulerValueDefault;tablePath.moveTo(stepStart, 0);tablePath.lineTo(stepStart, 0);tablePath.lineTo(tableEnd, 0);int startValue = minValue - (minValue > 0 ? 0 : minValue % rulerValue);int endValue = (maxValue + rulerValue);do {int startHeight = -getValueHeight(startValue);tablePath.moveTo(stepStart, startHeight);tablePath.lineTo(tableEnd, startHeight);drawRulerYText(canvas, String.valueOf(startValue), stepStart, startHeight);startValue += rulerValue;} while (startValue < endValue);canvas.drawPath(tablePath, circlePaint);drawRulerXValue(canvas);}private void drawRulerXValue(Canvas canvas) {if (linePoints == null) return;for (int i = 0; i < 7; i++) {Point point = linePoints[i];if (point == null) break;drawRulerXText(canvas, xline[i], linePoints[i].x - dip2px(10), 0);Log.i("qwe", "zhanguoqiang: " + linePoints[i]);}if (linePoints != null && linePoints[0] != null) {startX = linePoints[0].x- dip2px(10);endX = linePoints[6].x- dip2px(10);} else {Log.e("asd", "drawRulerXValue: linePoints空指针");}
//此处有崩溃}private void drawTable(Canvas canvas) {if (isPlayAnim) {Path path = new Path();PathMeasure measure = new PathMeasure(linePath, false);measure.getSegment(0, currentValue * measure.getLength(), path, true);canvas.drawPath(path, xianPaint);} else {canvas.drawPath(linePath, xianPaint);}mFillPath.reset();mFillPath.addPath(linePath);mFillPath.lineTo(endX, getViewDrawHeight() - dip2px(80));mFillPath.lineTo(startX, getViewDrawHeight() - dip2px(80));mFillPath.close();int save = canvas.save();canvas.clipPath(mFillPath);Drawable drawable = getAllDrawable();int left = startX, top = -1000, right = mWidth, bottom = endX;drawable.setBounds(left, top, right, bottom);drawable.draw(canvas);canvas.restoreToCount(save);}private Drawable getAllDrawable() {return getResources().getDrawable(R.drawable.path_fill_blue);}private void drawLinePoints(Canvas canvas) {if (linePoints == null) return;int pointCount = 7;float pointWidth = dip2px(pointWidthDP) / 2;if (isPlayAnim) {pointCount = Math.round(currentValue * 7);}for (int i = 0; i < pointCount; i++) {Point point = linePoints[i];startX = linePoints[0].x-dip2px(10);endX = linePoints[6].x-dip2px(10);if (point == null) break;if (i == 6)canvas.drawCircle(point.x - 20, point.y, pointWidth, pointPaint);if (index == 0) {canvas.drawLine(linePoints[0].x -  dip2px(10), 0, linePoints[0].x -  dip2px(10), point.y, datelinePaint);//       180, -26} else if (index == 1) {canvas.drawLine(linePoints[1].x -  dip2px(10), 0, linePoints[1].x -  dip2px(10), point.y, datelinePaint);//      309, -213} else if (index == 2) {canvas.drawLine(linePoints[2].x -  dip2px(10), 0, linePoints[2].x -  dip2px(10), point.y, datelinePaint);//      438, -138} else if (index == 3) {canvas.drawLine(linePoints[3].x -  dip2px(10), 0, linePoints[3].x -  dip2px(10), point.y, datelinePaint);//      567, -176} else if (index == 4) {canvas.drawLine(linePoints[4].x -  dip2px(10), 0, linePoints[4].x -  dip2px(10), point.y, datelinePaint);//      696, 0} else if (index == 5) {canvas.drawLine(linePoints[5].x -  dip2px(10), 0, linePoints[5].x -  dip2px(10), point.y, datelinePaint);//      825, -176} else if (index == 6) {canvas.drawLine(linePoints[6].x -  dip2px(10), 0, linePoints[6].x -  dip2px(10), point.y, datelinePaint);//      954, -168}
//            drawLinePointText(canvas, String.valueOf(dataList.get(i).getValue()), point.x - 30, point.y);}}private int getValueHeight(int value) {float valuePercent = Math.abs(value - minValue) * 100f / (Math.abs(maxValue - minValue) * 100f);Log.i("asd", "getValueHeight: " + (int) (getViewDrawHeight() * valuePercent + bottomSpace + 0.5f));return (int) (getViewDrawHeight() * valuePercent + 0.5f);}private float getViewDrawHeight() {Log.i("", "getViewDrawHeight: " + getMeasuredHeight() * heightPercent);return getMeasuredHeight() * heightPercent;}private void setupLine() {if (dataList.isEmpty()) return;int stepTemp = getTableStart();Point point = new Point();point.set(stepTemp, -getValueHeight(dataList.get(0).getValue()));//linePoints[0] = point;linePath.moveTo(point.x - dip2px(10), point.y);for (int i = 1; i < dataList.size(); i++) {DataBean data = dataList.get(i);Point next = new Point();next.set(stepTemp += stepSpace, -getValueHeight(data.getValue()));if (isBezierLine) {int cW = point.x + stepSpace / 2;Point p1 = new Point();p1.set(cW, point.y);Point p2 = new Point();p2.set(cW, next.y);linePath.cubicTo(p1.x - dip2px(10), p1.y, p2.x - dip2px(10), p2.y, next.x - dip2px(10), next.y);} else {linePath.lineTo(next.x - dip2px(10), next.y);}point = next;linePoints[i] = next;}isInitialized = true;}private int dip2px(float dipValue) {final float scale = getResources().getDisplayMetrics().density;return (int) (dipValue * scale + 0.5f);}private int sp2px(float spValue) {final float fontScale = getResources().getDisplayMetrics().scaledDensity;return (int) (spValue * fontScale + 0.5f);}private void refreshLayout() {resetParam();requestLayout();postInvalidate();}@Overridepublic boolean onTouchEvent(MotionEvent event) {float x = event.getX();float y = event.getY();switch (event.getAction()) {case MotionEvent.ACTION_UP:whichCircle(x, y);break;}return true;}private void whichCircle(float x, float y) {Log.i("qwe", "whichCircle: " + x);if (dip2px(17) < x && x < dip2px(77)) {index = 0;Log.i("zxc", "whichCircle: " + String.valueOf(dataList.get(0).getValue()));EventBus.getDefault().post(new SpetEvent(202, String.valueOf(dataList.get(0).getValue())));} else if ( dip2px(77) < x && x <  dip2px(125)) {index = 1;Log.i("zxc", "whichCircle: " + String.valueOf(dataList.get(1).getValue()));EventBus.getDefault().post(new SpetEvent(202, String.valueOf(dataList.get(1).getValue())));} else if ( dip2px(77) < x && x <  dip2px(173)) {index = 2;Log.i("zxc", "whichCircle: " + String.valueOf(dataList.get(2).getValue()));EventBus.getDefault().post(new SpetEvent(202, String.valueOf(dataList.get(2).getValue())));} else if (dip2px(173) < x && x < dip2px(221)) {index = 3;Log.i("zxc", "whichCircle: " + String.valueOf(dataList.get(3).getValue()));EventBus.getDefault().post(new SpetEvent(202, String.valueOf(dataList.get(3).getValue())));} else if (dip2px(221) < x && x <dip2px(269) ) {index = 4;Log.i("zxc", "whichCircle: " + String.valueOf(dataList.get(4).getValue()));EventBus.getDefault().post(new SpetEvent(202, String.valueOf(dataList.get(4).getValue())));} else if (dip2px(269) < x && x < dip2px(283)) {index = 5;Log.i("zxc", "whichCircle: " + String.valueOf(dataList.get(5).getValue()));EventBus.getDefault().post(new SpetEvent(202, String.valueOf(dataList.get(5).getValue())));} else if (x > dip2px(283)) {index = 6;Log.i("zxc", "whichCircle: " + String.valueOf(dataList.get(index).getValue()));EventBus.getDefault().post(new SpetEvent(202, String.valueOf(dataList.get(6).getValue())));}refreshLayout();/*   if (x == 180) {} else if (x == 324) {} else if (x == 468) {} else if (x == 612) {} else if (x == 756) {} else if (x == 900) {} else if (x == 1044) {}*/}/*** 设置数据** @param dataList*/public void setData(List<DataBean> dataList) {if (dataList == null) {throw new RuntimeException("dataList cannot is null!");}if (dataList.isEmpty()) return;this.dataList.clear();this.dataList.addAll(dataList);maxValue = Collections.max(this.dataList, new Comparator<DataBean>() {@Overridepublic int compare(DataBean o1, DataBean o2) {return o1.getValue() - o2.getValue();}}).getValue();minValue = Collections.min(this.dataList, new Comparator<DataBean>() {@Overridepublic int compare(DataBean o1, DataBean o2) {return o1.getValue() - o2.getValue();}}).getValue();refreshLayout();}public void setDate(String[] dateList) {if (dateList == null) {throw new RuntimeException("dateList cannot is null!");}if (dateList.length == 0) return;this.xline = null;this.xline = dateList;refreshLayout();}public void playAnim() {this.isPlayAnim = true;if (isAnimating) return;if (valueAnimator != null) {valueAnimator.start();}}public static class DataBean {int key;public DataBean(int key) {this.key = key;}public int getValue() {return key;}}public void setRulerYSpace(int space) {if (space <= 0) {space = rulerValueDefault;}this.rulerValue = space;refreshLayout();}
}

资源文件

drawable文件夹下

path_fill_blue.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"><gradientandroid:startColor="@color/blue_transparent_start"android:endColor="@color/blue_transparent_end"android:angle="90"/>
</shape>

path_fill_green.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"><gradientandroid:startColor="@color/green_transparent_start"android:endColor="@color/green_transparent_end"android:angle="0"/>
</shape>

path_fill_pink.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"><gradientandroid:angle="0"android:endColor="@color/pink_transparent_end"android:startColor="@color/pink_transparent_start" />
</shape>

colors.xml文件下

<color name="blue_transparent_start">#0000</color>
<color name="blue_transparent_end">#505FB4F8</color>
<color name="green_transparent_start">#004fd4d0</color>
<color name="green_transparent_end">#804fd4d0</color>
<color name="pink_transparent_start">#00FFB6C1</color>
<color name="pink_transparent_end">#80FFB6C1</color>

结束。

调用

(写在Activity或者Fragment方法中的)我是写在 onCreate()方法中了

↓↓↓

ArrayList<Integer> listValueNum = new ArrayList<>();listValueNum.add(1000);
listValueNum.add(6000);
listValueNum.add(4000);
listValueNum.add(5000);
listValueNum.add(300);
listValueNum.add(5000);
listValueNum.add(4800);
List<UshareChatView.Data> datas = new ArrayList<>();
for (int value : listValueNum) {UshareChatView.Data data = new UshareChatView.Data(value);datas.add(data);
ushareChatView.setData(datas);
if (Collections.max(listValueNum) < 1200) {ushareChatView.setRulerYSpace(30);
} else if (Collections.max(listValueNum) > 1200 && Collections.max(listValueNum) < 5000) {ushareChatView.setRulerYSpace(400);
} else {ushareChatView.setRulerYSpace(5000);
}
if (ushareChatView != null) {ushareChatView.playAnim();//曲线动画
}
}
//获取当前日期往前推一个星期   public String getOtherDate(int value) {DateFormat dateFormat = new SimpleDateFormat("dd");Calendar calendar = Calendar.getInstance();calendar.set(Calendar.HOUR_OF_DAY, value);String otherDate = dateFormat.format(calendar.getTime());
//        Log.i("asd", "getOtherDate: " + otherDate);return otherDate;}

资源文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@color/white"android:orientation="vertical"><UshareChatViewandroid:id="@+id/ushareChatView"android:layout_width="328dp"android:layout_height="115dp" />
</LinearLayout>

//手敲操作 欢迎指正 

《高仿支付宝运动轨迹七日曲线图》相关推荐

  1. ComeFuture英伽学院——2020年 全国大学生英语竞赛【C类初赛真题解析】(持续更新)

    视频:ComeFuture英伽学院--2019年 全国大学生英语竞赛[C类初赛真题解析]大小作文--详细解析 课件:[课件]2019年大学生英语竞赛C类初赛.pdf 视频:2020年全国大学生英语竞赛 ...

  2. ComeFuture英伽学院——2019年 全国大学生英语竞赛【C类初赛真题解析】大小作文——详细解析

    视频:ComeFuture英伽学院--2019年 全国大学生英语竞赛[C类初赛真题解析]大小作文--详细解析 课件:[课件]2019年大学生英语竞赛C类初赛.pdf 视频:2020年全国大学生英语竞赛 ...

  3. 信息学奥赛真题解析(玩具谜题)

    玩具谜题(2016年信息学奥赛提高组真题) 题目描述 小南有一套可爱的玩具小人, 它们各有不同的职业.有一天, 这些玩具小人把小南的眼镜藏了起来.小南发现玩具小人们围成了一个圈,它们有的面朝圈内,有的 ...

  4. 信息学奥赛之初赛 第1轮 讲解(01-08课)

    信息学奥赛之初赛讲解 01 计算机概述 系统基本结构 信息学奥赛之初赛讲解 01 计算机概述 系统基本结构_哔哩哔哩_bilibili 信息学奥赛之初赛讲解 02 软件系统 计算机语言 进制转换 信息 ...

  5. 信息学奥赛一本通习题答案(五)

    最近在给小学生做C++的入门培训,用的教程是信息学奥赛一本通,刷题网址 http://ybt.ssoier.cn:8088/index.php 现将部分习题的答案放在博客上,希望能给其他有需要的人带来 ...

  6. 信息学奥赛一本通习题答案(三)

    最近在给小学生做C++的入门培训,用的教程是信息学奥赛一本通,刷题网址 http://ybt.ssoier.cn:8088/index.php 现将部分习题的答案放在博客上,希望能给其他有需要的人带来 ...

  7. 信息学奥赛一本通 提高篇 第六部分 数学基础 相关的真题

    第1章   快速幂 1875:[13NOIP提高组]转圈游戏 信息学奥赛一本通(C++版)在线评测系统 第2 章  素数 第 3 章  约数 第 4 章  同余问题 第 5 章  矩阵乘法 第 6 章 ...

  8. 信息学奥赛一本通题目代码(非题库)

    为了完善自己学c++,很多人都去读相关文献,就比如<信息学奥赛一本通>,可又对题目无从下手,从今天开始,我将把书上的题目一 一的解析下来,可以做参考,如果有错,可以告诉我,将在下次解析里重 ...

  9. 信息学奥赛一本通(C++版) 刷题 记录

    总目录详见:https://blog.csdn.net/mrcrack/article/details/86501716 信息学奥赛一本通(C++版) 刷题 记录 http://ybt.ssoier. ...

  10. 最近公共祖先三种算法详解 + 模板题 建议新手收藏 例题: 信息学奥赛一本通 祖孙询问 距离

    首先什么是最近公共祖先?? 如图:红色节点的祖先为红色的1, 2, 3. 绿色节点的祖先为绿色的1, 2, 3, 4. 他们的最近公共祖先即他们最先相交的地方,如在上图中黄色的点就是他们的最近公共祖先 ...

最新文章

  1. NSNotification先注册监听,再发送消息
  2. 英伟达新核弹GPU:4nm制程800亿晶体管,20张即可承载全球互联网流量,全新Hopper架构太炸了...
  3. 深度学习核心技术精讲100篇(十一)-Google利器超强特征提取网络(Transformer)
  4. 提现接口网站 php,API提现接口
  5. Java Swing Mysql学生成绩管理系统
  6. 敏捷开发绩效管理之六:敏捷开发生产率(中)(功能点分析,FPA,简化的功能点)...
  7. redis命令_INCR
  8. 使用一个虚拟环境,但是运用其他环境中的库!【pycharm】
  9. 学生id号码是什么意思_ID是什么意思?
  10. android pad刷机,平板刷机图文教程详解!小编手把手教你安卓平板电脑怎么刷机
  11. .Net core 跨平台UI解决方案
  12. 系统函数,频率响应定义
  13. 计算机三维成像在哪些领域有运用,【图】三维动画类别及运用领域,三维动画分类介绍...
  14. 分享软件测试人员必备的60个测试工具,赶紧收藏起来
  15. Jenkin:Failed to start Jenkins Continuous Integration Server问题解决
  16. 《黑客与画家》读书笔记(六)
  17. 风浪模拟数据准备步骤(MOW/SWAN):如何从ECMWF-EAR下载数据
  18. kitty终端使用笔记
  19. html怎样使动画循环,html – 如何在css动画循环之间添加延迟
  20. 数字集成电路——电路、系统与设计

热门文章

  1. 简单的言语介绍一下什么是程序员
  2. EMW3080+STC15轻松实现设备上云1(阿里云物联网平台、智能生活开放平台)
  3. 来了,2020全球算力大会暨新基建矿业峰会,首批重磅嘉宾阵容出炉!
  4. 安装kali Linux到U盘
  5. 学习与坚持是我的人生信仰
  6. 细致的网站开发流程有哪些呢?
  7. 微信屏蔽网址解决办法 微信QQ已经被屏蔽的域名怎么做跳转
  8. C++周末训练题-机器人迷宫(BFS)
  9. 清橙OJ A1046 加法器
  10. 高一数学微课堂【教学视频】