import std.stdio, std.conv, std.string, std.array, std.range, std.algorithm, std.container;
import std.math, std.random, std.bigint, std.datetime, std.format;
bool DEBUG = 0; void log(A ...)(lazy A a){ if(DEBUG) print(a); }
void main(string[] args){ args ~= ["", ""]; string cmd = args[1]; if(cmd == "-debug") DEBUG = 1;
if(cmd == "-gen") gen; else if(cmd == "-jury") jury; else solve; } 
void print(){ writeln(""); } void print(T)(T t){ writeln(t); } void print(T, A ...)(T t, A a){ std.stdio.write(t, " "), print(a); }
string unsplit(T)(T xs){ return xs.array.to!(string[]).join(" "); }
string picture(bool[] xs){ return xs.array.map!(x => x? '#': '.').array; } string picture(bool[][] xf){ return xf.map!(xs => xs.picture).array.join("\n"); }
string scan(){ static string[] ss; while(!ss.length) ss = readln.chomp.split; string res = ss[0]; ss.popFront; return res; }
T scan(T)(){ return scan.to!T; } T[] scan(T)(int n){ return n.iota.map!(i => scan!T()).array; }
T lowerTo(T)(ref T x, T y){ if(x > y) x = y; return x; } T raiseTo(T)(ref T x, T y){ if(x < y) x = y; return x; }

// ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- //
void gen(){
}
void jury(){
}
int alim = 300_009;
void solve(){
    if(DEBUG) alim = 30;

    int n = scan!int, k = scan!int;
    int[] as = scan!int(n);
    log("as:", as);

    auto seg = new SegTree!int(0, alim, (int x, int y) => max(x, y), 0);
    foreach(a; 0 .. alim) seg.setValue(a, 0);
    log("seg:", seg);

    int[] xs = new int[](n);
    foreach(int i, a; as){
        int l = max(0, a - k);
        int r = min(alim, a + k + 1); 
        log("i:", i, "l:", l, "r:", r);
        xs[i] = seg.getValue(l, r) + 1;
        log("x:", xs[i]);
        seg.setValue(a, xs[i]);
        log("seg:", seg);
    }

    int ans = seg.getValue(0, alim);
    ans.print;

}


/*
セグメント木 区分木 segtree segment tree
1点に書き込み、範囲で読み出す。
たとえば [l, r) の最大値を求めるなど。
引数
a, b　添字の範囲。 この意味はa から b - 1 までなので注意。
marge　左の子と右の子から自分の値をきめる関数（たとえばmax）
neutral　すべての x に対して marge(x, z) = x をみたすz（たとえば-infty）
*/
class SegTree(T){
	T value;
	T neutral;
	SegTree left, right; // 左の子(a <= x < c)、右の子(c <= x < b)
	bool hasValue;
	bool isTerminal;
	int a, b; // a <= x < b を担当する
	T delegate(T, T) marge;
	this(int a, int b, T delegate(T, T) marge, T neutral = T.init){
		this.a = a, this.b = b;
		this.marge = marge;
		this.neutral = neutral;
		if(b - a == 1){
			this.isTerminal = 1;
		}
		else{
			int c = (a + b) / 2;
			this.left = new SegTree(a, c, marge, neutral);
			this.right = new SegTree(c, b, marge, neutral);
		}
	}
	
	// [a, b) における値を読む ※[a, b) はこのノードの担当区間とかぶっていなくてもよい
	T getValue(int a, int b){
		if(b <= this.a || this.b <= a) return neutral;
		if(a <= this.a && this.b <= b){
			if(! this.hasValue){
				T v1 = this.left.getValue(a, b), v2 = this.right.getValue(a, b);
				T v = marge(v1, v2);
				this.value = v;
				this.hasValue = 1;
			}
			return this.value;
		}
		else{
			T v1 = this.left.getValue(a, b), v2 = this.right.getValue(a, b);
			T v = marge(v1, v2);
			return v;
		}
	}
	
	
	// i における値を設定
	void setValue(int i, T value){
		assert(a <= i && i < b);
		this.hasValue = 0;
		if(this.isTerminal){
			this.hasValue = 1;
			this.value = value;
		}
		else if(i < left.b) left.setValue(i, value);
		else right.setValue(i, value);
	}
	
	// 配列に変換したもの（デバッグ用）
	T[] array(){
		if(this.isTerminal) return [this.value];
		else return this.left.array ~ this.right.array;
	}
	
	// 文字列に変換したもの（デバッグ用）
	override string toString(){
		return this.array.to!string;
	}
}

Measured memory_bytes: 64704