我们专注攀枝花网站设计 攀枝花网站制作 攀枝花网站建设
成都网站建设公司服务热线:400-028-6601

网站建设知识

十年网站开发经验 + 多家企业客户 + 靠谱的建站团队

量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决

java刷题代码 Java代码题

学习Java应该关注哪些网站

推荐10个常用的Java网站

创新互联是专业的射洪网站建设公司,射洪接单;提供成都网站建设、网站制作,网页设计,网站设计,建网站,PHP网站建设等专业做网站服务;采用PHP框架,可快速的进行射洪网站开发网页制作和功能扩展;专业做搜索引擎喜爱的网站,专业的做网站团队,希望更多企业前来合作!

Stackoverflow

Stackoverflow.com 可能是编程界中最流行的网站了,该网站有成千上万个好问题和答案。学习API或者编程语言,通常依赖于代码示例,stackoverflow就可以提供大量的代码片段。

Stackoverflow的另一个优点在于它的社交性。你可以在一些特定的标签下查看问题,比如“Java”、“regex”,你就会看到哪些是高频问题。这对于学习,以及Java博主书写热门话题都是一种非常好的资源。

DZone

这是一个非常有趣的网站,有相当多的开发者在这个网站上分享他们博客文章。就像一场冒险一样,在这里,你永远不知道下一秒会看到什么内容。

LeetCode

如果有Java方面的面试问题,例如“在Java中,内存中的数组是什么样的”,你可以从很多Java教程中找到答案。但是,遇到类似于“如何将SortedArray转化成一个BalancedTree”这样的问题,你就应该去求助LeetCode了。LeetCode包含一系列算法问题, 它能为有关信息技术的面试提供一个社会性的平台。这个网站最好的地方就是,它可以通过大小不同的数据在线检查你的代码是否正确。很多人认为,面试成功的关键在于重复这三个重要步骤:编码-阅读-讨论。

Java SE技术文档

这个网站包含了在使用Java SE API时会用到的所有文档,即使你是Java开发牛人,我敢肯定在这里你仍能发现一些有用的东西。比如,你可以阅读一些像“Java类的本质”、“部署”这样的教程。

Github

你也许知道可以免费的将你的项目托管在哪,但你不一定知道它还是一个学习当今流行的Java库和框架的优秀资源。比如,你想学 Spring MVC Framework,你可以搜索并且找到一些开源的项目。遵循“照葫芦画瓢”的原则,你能够通过实例快速的学习框架,尤其是你已经具有使用类似框架的经验。

Coursera

这是有关视频讲座的最好网站,在这里你可以找到许多顶尖学校的著名教授的优秀计算机科学课程。这些教授中,有些甚至是一些计算机科学领域的发明者。

Java World

这个网站包含了大量的Java教程,涉及各种各样的话题。其中很多文章都写的很好,并且有图片、插图进行说明。它可以被用来当作深度学习的教科书。

DevStore

这个网站是针对开发者做的一个服务商店,为开发者提供从设计开发到运营推广一站式的解决方案。开发者在任何阶段需要某种服务时,都可通过DevStore进行参数对比,查看评测、快速体验等来了解,不再需要一一搜索。

Wikipedia 维基百科

这个网站是查询或学习几乎所有概念的最好的资源之一。例如,作为一个资深的Java开发人员,你可能只是想了解一些概念并不想深度研究。这里是一个可以免费查询最新信息的好地方。例如,什么是面向服务的编程?另外,它还能为你的写作提供大量素材。比如,同一个词在不同的领域可能会有完全不同的含义。有时,研究这些词在不同领域的不同含义是非常有意思的。

Program Creek

与以上几个网站相比,Programcreek.com在规模上要小很多。但是规模小也有优点,它在维护方面做的更好,读起来更有趣。在这里,你可以找到其他任何网站都不曾涉及到的话题,而且几乎每篇文章都包含漂亮的插图或者示例代码。它包含了来自不同领域的人发表的文章(科研、工业),并且经常为Java开发者提供优质材料。希望有一天,它也会出现在一些人的网站前十名排行名单中。

注:当然,对于Java开发牛人来说还有很多其它不错的网站。如果你认为有其他的网站也应该列在这里,请留言,我以后也会加进去的。谢谢。

新手java在哪里刷题?

LearnJava 在线 这是一个非常不错的学习 Java 的在线网站,纯免费。

Java是一门面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征。

Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程。

Java具有简单性、面向对象、分布式、健壮性、安全性、平台独立与可移植性、多线程、动态性等特点。Java可以编写桌面应用程序、Web应用程序、分布式系统和嵌入式系统应用程序等。

华为mate paid能用java编程么

可以。

准备华为matepad,AidLearning软件,其中华为应用市场中就有该软件,选择适合arm架构的JDK。

平板毕竟是更适合娱乐的设备,因此适合直接在平板上进行Java编程的软件还是很少的。虽然可以在应用市场找到一款名为Java编译器的软件,但是既没有智能提示,又没有代码补全,在上面刷题和直接在leetcode上刷没多大区别。

AIdLearning虽然是主打人工智能,但是它是把整个Debian系统搬到了安卓上,并且还内置了vscode这样,利用AidLearning中的vscode就可以比较简单的在手机上搭建Java编程环境了。AidLearning软件在应用市场中就可以搜到,直接安装即可。

前端可以用java写力扣吗

前端刷题用js还是java

前端刷题用js还是java_用JavaScript刷LeetCode的正确姿势

韦桂超

原创

关注

0点赞·1164人阅读

虽然很多人都觉得前端算法弱,但其实 JavaScript 也可以刷题啊!最近两个月断断续续刷完了 leetcode 前 200 的 middle + hard ,总结了一些刷题常用的模板代码。走过路过发现 bug 请指出,拯救一个辣鸡(但很帅)的少年就靠您啦!

常用函数

包括打印函数和一些数学函数。

const _max =Math.max.bind(Math);

const _min=Math.min.bind(Math);

const _pow=Math.pow.bind(Math);

const _floor=Math.floor.bind(Math);

const _round=Math.round.bind(Math);

const _ceil=Math.ceil.bind(Math);

const log=console.log.bind(console);//const log = _ = {}

log 在提交的代码中当然是用不到的,不过在调试时十分有用。但是当代码里面加了很多 log 的时候,提交时还需要一个个注释掉就相当麻烦了,只要将 log 赋值为空函数就可以了。

举一个简单的例子,下面的代码是可以直接提交的。

//计算 1+2+...+n//const log = console.log.bind(console);

const log = _ ={}functionsumOneToN(n) {

let sum= 0;for (let i = 1; i = n; i++) {

sum+=i;

log(`i=${i}: sum=${sum}`);

}returnsum;

}

sumOneToN(10);

位运算的一些小技巧

判断一个整数 x 的奇偶性: x 1 = 1 (奇数) , x 1 = 0 (偶数)

求一个浮点数 x 的整数部分: ~~x ,对于正数相当于 floor(x) 对于负数相当于 ceil(-x)

计算 2 ^ n : 1 n 相当于 pow(2, n)

计算一个数 x 除以 2 的 n 倍: x n 相当于 ~~(x / pow(2, n))

判断一个数 x 是 2 的整数幂(即 x = 2 ^ n ): x (x - 1) = 0

※注意※:上面的位运算只对32位带符号的整数有效,如果使用的话,一定要注意数!据!范!围!

记住这些技巧的作用:

提升运行速度 ❌

提升逼格 ✅

举一个实用的例子,快速幂(原理自行google)

//计算x^n n为整数

functionqPow(x, n) {

let result= 1;while(n) {if (n 1) result *= x; //同 if(n%2)

x = x *x;

n= 1; //同 n=floor(n/2)

}returnresult;

}

链表

刚开始做 LeetCode 的题就遇到了很多链表的题。恶心心。最麻烦的不是写题,是调试啊!!于是总结了一些链表的辅助函数。

/**

* 链表节点

* @param {*} val

* @param {ListNode} next*/

function ListNode(val, next = null) {this.val =val;this.next =next;

}/**

* 将一个数组转为链表

* @param {array} a

* @return {ListNode}*/const getListFromArray= (a) ={

let dummy= newListNode()

let pre=dummy;

a.forEach(x= pre = pre.next = newListNode(x));returndummy.next;

}/**

* 将一个链表转为数组

* @param {ListNode} node

* @return {array}*/const getArrayFromList= (node) ={

let a=[];while(node) {

a.push(node.val);

node=node.next;

}returna;

}/**

* 打印一个链表

* @param {ListNode} node*/const logList= (node) ={

let str= 'list: ';while(node) {

str+= node.val + '-';

node=node.next;

}

str+= 'end';

log(str);

}

还有一个常用小技巧,每次写链表的操作,都要注意判断表头,如果创建一个空表头来进行操作会方便很多。

let dummy = newListNode();//返回

return dummy.next;

使用起来超爽哒~举个例子。@leetcode 82。题意就是删除链表中连续相同值的节点。

/** @lc app=leetcode id=82 lang=javascript

*

* [82] Remove Duplicates from Sorted List II*/

/**

* @param {ListNode} head

* @return {ListNode}*/

var deleteDuplicates = function(head) {//空指针或者只有一个节点不需要处理

if (head === null || head.next === null) returnhead;

let dummy= newListNode();

let oldLinkCurrent=head;

let newLinkCurrent=dummy;while(oldLinkCurrent) {

let next=oldLinkCurrent.next;//如果当前节点和下一个节点的值相同 就要一直向前直到出现不同的值

if (next oldLinkCurrent.val ===next.val) {while (next oldLinkCurrent.val ===next.val) {

next=next.next;

}

oldLinkCurrent=next;

}else{

newLinkCurrent= newLinkCurrent.next =oldLinkCurrent;

oldLinkCurrent=oldLinkCurrent.next;

}

}

newLinkCurrent.next= null; //记得结尾置空~

logList(dummy.next);returndummy.next;

};

deleteDuplicates(getListFromArray([1,2,3,3,4,4,5]));

deleteDuplicates(getListFromArray([1,1,2,2,3,3,4,4,5]));

deleteDuplicates(getListFromArray([1,1]));

deleteDuplicates(getListFromArray([1,2,2,3,3]));

本地运行结果

list: 1-2-5-end

list:5-end

list: end

list:1-end

是不是很方便!

矩阵(二维数组)

矩阵的题目也有很多,基本每一个需要用到二维数组的题,都涉及到初始化,求行数列数,遍历的代码。于是简单提取出来几个函数。

/**

* 初始化一个二维数组

* @param {number} r 行数

* @param {number} c 列数

* @param {*} init 初始值*/const initMatrix= (r, c, init = 0) = new Array(r).fill().map(_ = newArray(c).fill(init));/**

* 获取一个二维数组的行数和列数

* @param {any[][]} matrix

* @return [row, col]*/const getMatrixRowAndCol= (matrix) = matrix.length === 0 ? [0, 0] : [matrix.length, matrix[0].length];/**

* 遍历一个二维数组

* @param {any[][]} matrix

* @param {Function} func*/const matrixFor= (matrix, func) ={

matrix.forEach((row, i)={

row.forEach((item, j)={

func(item, i, j, row, matrix);

});

})

}/**

* 获取矩阵第index个元素 从0开始

* @param {any[][]} matrix

* @param {number} index*/

functiongetMatrix(matrix, index) {

let col= matrix[0].length;

let i= ~~(index /col);

let j= index - i *col;returnmatrix[i][j];

}/**

* 设置矩阵第index个元素 从0开始

* @param {any[][]} matrix

* @param {number} index*/

functionsetMatrix(matrix, index, value) {

let col= matrix[0].length;

let i= ~~(index /col);

let j= index - i *col;return matrix[i][j] =value;

}

找一个简单的矩阵的题示范一下用法。@leetcode 566。题意就是将一个矩阵重新排列为r行c列。

/** @lc app=leetcode id=566 lang=javascript

*

* [566] Reshape the Matrix*/

/**

* @param {number[][]} nums

* @param {number} r

* @param {number} c

* @return {number[][]}*/

var matrixReshape = function(nums, r, c) {//将一个矩阵重新排列为r行c列

//首先获取原来的行数和列数

let [r1, c1] =getMatrixRowAndCol(nums);

log(r1, c1);//不合法的话就返回原矩阵

if (!r1 || r1 * c1 !== r * c) returnnums;//初始化新矩阵

let matrix =initMatrix(r, c);//遍历原矩阵生成新矩阵

matrixFor(nums, (val, i, j) ={

let index= i * c1 + j; //计算是第几个元素

log(index);

setMatrix(matrix, index, val);//在新矩阵的对应位置赋值

});returnmatrix;

};

let x= matrixReshape([[1],[2],[3],[4]], 2, 2);

log(x)

二叉树

当我做到二叉树相关的题目,我发现,我错怪链表了,呜呜呜这个更恶心。

当然对于二叉树,只要你掌握先序遍历,后序遍历,中序遍历,层序遍历,递归以及非递归版,先序中序求二叉树,先序后序求二叉树,基本就能AC大部分二叉树的题目了(我瞎说的)。

二叉树的题目 input 一般都是层序遍历的数组,所以写了层序遍历数组和二叉树的转换,方便调试。

function TreeNode(val, left = null, right = null) {this.val =val;this.left =left;this.right =right;

}/**

* 通过一个层次遍历的数组生成一棵二叉树

* @param {any[]} array

* @return {TreeNode}*/

functiongetTreeFromLayerOrderArray(array) {

let n=array.length;if (!n) return null;

let index= 0;

let root= new TreeNode(array[index++]);

let queue=[root];while(index

let top=queue.shift();

let v= array[index++];

top.left= v == null ? null : newTreeNode(v);if (index

let v= array[index++];

top.right= v == null ? null : newTreeNode(v);

}if(top.left) queue.push(top.left);if(top.right) queue.push(top.right);

}returnroot;

}/**

* 层序遍历一棵二叉树 生成一个数组

* @param {TreeNode} root

* @return {any[]}*/

functiongetLayerOrderArrayFromTree(root) {

let res=[];

let que=[root];while(que.length) {

let len=que.length;for (let i = 0; i len; i++) {

let cur=que.shift();if(cur) {

res.push(cur.val);

que.push(cur.left, cur.right);

}else{

res.push(null);

}

}

}while (res.length 1 res[res.length - 1] == null) res.pop(); //删掉结尾的 null

returnres;

}

一个例子,@leetcode 110,判断一棵二叉树是不是平衡二叉树。

/**

* @param {TreeNode} root

* @return {boolean}*/

var isBalanced = function(root) {if (!root) return true; //认为空指针也是平衡树吧

//获取一个二叉树的深度

const d = (root) ={if (!root) return 0;return _max(d(root.left), d(root.right)) + 1;

}

let leftDepth=d(root.left);

let rightDepth=d(root.right);//深度差不超过 1 且子树都是平衡树

if (_min(leftDepth, rightDepth) + 1 =_max(leftDepth, rightDepth) isBalanced(root.left) isBalanced(root.right)) return true;return false;

};

log(isBalanced(getTreeFromLayerOrderArray([3,9,20,null,null,15,7])));

log(isBalanced(getTreeFromLayerOrderArray([1,2,2,3,3,null,null,4,4])));

二分查找

参考 C++ STL 中的 lower_bound 和 upper_bound 。这两个函数真的很好用的!

/**

* 寻找=target的最小下标

* @param {number[]} nums

* @param {number} target

* @return {number}*/

functionlower_bound(nums, target) {

let first= 0;

let len=nums.length;while (len 0) {

let half= len 1;

let middle= first +half;if (nums[middle]

first= middle + 1;

len= len - half - 1;

}else{

len=half;

}

}returnfirst;

}/**

* 寻找target的最小下标

* @param {number[]} nums

* @param {number} target

* @return {number}*/

functionupper_bound(nums, target) {

let first= 0;

let len=nums.length;while (len 0) {

let half= len 1;

let middle= first +half;if (nums[middle] target) {

len=half;

}else{

first= middle + 1;

len= len - half - 1;

}

}returnfirst;

}

照例,举个例子,@leetcode 34。题意是给一个排好序的数组和一个目标数字,求数组中等于目标数字的元素最小下标和最大下标。不存在就返回 -1。

/** @lc app=leetcode id=34 lang=javascript

*

* [34] Find First and Last Position of Element in Sorted Array*/

/**

* @param {number[]} nums

* @param {number} target

* @return {number[]}*/

var searchRange = function(nums, target) {

let lower=lower_bound(nums, target);

let upper=upper_bound(nums, target);

let size=nums.length;//不存在返回 [-1, -1]

if (lower = size || nums[lower] !== target) return [-1, -1];return [lower, upper - 1];

};

在 VS Code 中刷 LeetCode

前面说的那些模板,难道每一次打开新的一道题都要复制一遍么?当然不用啦。

首先配置代码片段 选择 Code - Preferences - User Snippets ,然后选择 JavaScript

然后把文件替换为下面的代码:

{"leetcode template": {"prefix": "@lc","body": ["const _max = Math.max.bind(Math);","const _min = Math.min.bind(Math);","const _pow = Math.pow.bind(Math);","const _floor = Math.floor.bind(Math);","const _round = Math.round.bind(Math);","const _ceil = Math.ceil.bind(Math);","const log = console.log.bind(console);","// const log = _ = {}","/**************** 链表 ****************/","/**"," * 链表节点"," * @param {*} val"," * @param {ListNode} next"," */","function ListNode(val, next = null) {"," this.val = val;"," this.next = next;","}","/**"," * 将一个数组转为链表"," * @param {array} array"," * @return {ListNode}"," */","const getListFromArray = (array) = {"," let dummy = new ListNode()"," let pre = dummy;"," array.forEach(x = pre = pre.next = new ListNode(x));"," return dummy.next;","}","/**"," * 将一个链表转为数组"," * @param {ListNode} list"," * @return {array}"," */","const getArrayFromList = (list) = {"," let a = [];"," while (list) {"," a.push(list.val);"," list = list.next;"," }"," return a;","}","/**"," * 打印一个链表"," * @param {ListNode} list "," */","const logList = (list) = {"," let str = 'list: ';"," while (list) {"," str += list.val + '-';"," list = list.next;"," }"," str += 'end';"," log(str);","}","/**************** 矩阵(二维数组) ****************/","/**"," * 初始化一个二维数组"," * @param {number} r 行数"," * @param {number} c 列数"," * @param {*} init 初始值"," */","const initMatrix = (r, c, init = 0) = new Array(r).fill().map(_ = new Array(c).fill(init));","/**"," * 获取一个二维数组的行数和列数"," * @param {any[][]} matrix"," * @return [row, col]"," */","const getMatrixRowAndCol = (matrix) = matrix.length === 0 ? [0, 0] : [matrix.length, matrix[0].length];","/**"," * 遍历一个二维数组"," * @param {any[][]} matrix "," * @param {Function} func "," */","const matrixFor = (matrix, func) = {"," matrix.forEach((row, i) = {"," row.forEach((item, j) = {"," func(item, i, j, row, matrix);"," });"," })","}","/**"," * 获取矩阵第index个元素 从0开始"," * @param {any[][]} matrix "," * @param {number} index "," */","function getMatrix(matrix, index) {"," let col = matrix[0].length;"," let i = ~~(index / col);"," let j = index - i * col;"," return matrix[i][j];","}","/**"," * 设置矩阵第index个元素 从0开始"," * @param {any[][]} matrix "," * @param {number} index "," */","function setMatrix(matrix, index, value) {"," let col = matrix[0].length;"," let i = ~~(index / col);"," let j = index - i * col;"," return matrix[i][j] = value;","}","/**************** 二叉树 ****************/","/**"," * 二叉树节点"," * @param {*} val"," * @param {TreeNode} left"," * @param {TreeNode} right"," */","function TreeNode(val, left = null, right = null) {"," this.val = val;"," this.left = left;"," this.right = right;","}","/**"," * 通过一个层次遍历的数组生成一棵二叉树"," * @param {any[]} array"," * @return {TreeNode}"," */","function getTreeFromLayerOrderArray(array) {"," let n = array.length;"," if (!n) return null;"," let index = 0;"," let root = new TreeNode(array[index++]);"," let queue = [root];"," while(index n) {"," let top = queue.shift();"," let v = array[index++];"," top.left = v == null ? null : new TreeNode(v);"," if (index n) {"," let v = array[index++];"," top.right = v == null ? null : new TreeNode(v);"," }"," if (top.left) queue.push(top.left);"," if (top.right) queue.push(top.right);"," }"," return root;","}","/**"," * 层序遍历一棵二叉树 生成一个数组"," * @param {TreeNode} root "," * @return {any[]}"," */","function getLayerOrderArrayFromTree(root) {"," let res = [];"," let que = [root];"," while (que.length) {"," let len = que.length;"," for (let i = 0; i len; i++) {"," let cur = que.shift();"," if (cur) {"," res.push(cur.val);"," que.push(cur.left, cur.right);"," } else {"," res.push(null);"," }"," }"," }"," while (res.length 1 res[res.length - 1] == null) res.pop(); // 删掉结尾的 null"," return res;","}","/**************** 二分查找 ****************/","/**"," * 寻找=target的最小下标"," * @param {number[]} nums"," * @param {number} target"," * @return {number}"," */","function lower_bound(nums, target) {"," let first = 0;"," let len = nums.length;",""," while (len 0) {"," let half = len 1;"," let middle = first + half;"," if (nums[middle] target) {"," first = middle + 1;"," len = len - half - 1;"," } else {"," len = half;"," }"," }"," return first;","}","","/**"," * 寻找target的最小下标"," * @param {number[]} nums"," * @param {number} target"," * @return {number}"," */","function upper_bound(nums, target) {"," let first = 0;"," let len = nums.length;",""," while (len 0) {"," let half = len 1;"," let middle = first + half;"," if (nums[middle] target) {"," len = half;"," } else {"," first = middle + 1;"," len = len - half - 1;"," }"," }"," return first;","}","$1"],"description": "LeetCode常用代码模板"}

}

java1+x中级只刷题能过吗

java1+x中级只刷题能过,

其实这个问题是因人而异,如果你基础知识牢固,学习能力强,有工作经验,刷几套真题对于通过中级会计考试是没问题的;但是如果你基础薄弱,学习能力弱,只是刷几套真题,考过的可能性不大。 建议时间充足的话还是要全面掌握

耗时7天我终于把LeetCode刷通关:数组十七连,真是不简单

大家好,我是老三,一个刷题困难户,接下来我们开始数组类型算法的刷题之旅!

数组

数组基本上是我们最熟悉的数据结构了,刚会写“Hello World”不久,接着就是“杨辉三角”之类的练习。

数组结构

上图是一个字符数组的例子。

因为内存空间连续,所以可以直接通过下标获取对应的元素。

但是删除就麻烦一点,相当于填坑,一个元素被移走,留下的坑,需要其它元素来填上。

删除元素

在Java中,多维数组的存储本质上也是一个行优先的一维数组。

我们都知道,在Java中的 “=” 用在基本数据类型上,是值传递,用在引用数据类型上,是引用传递。

这一块展开可以写一篇文章,我们只简单看个例子:

大家可以看到,newArray改变了,array也跟着变了。

为什么呢?

在Java中,数组是引用数组类型。array、newArray都是存储在栈中的引用,它们指向堆中真正存储的数组对象。

所以改变了newArray,实际是改变了newArray指向的数组。

数组引用传递

这一点是我们刷题需要注意的,复制数组需要在循环中一个个复制。

题目:704. 二分查找 ()

难度:简单

描述:

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。

题目示例

思路:

二分查找可以说我们都很熟了。

因为数组是有序的,所以定义三个指针,low、high、mid,每次与中间指针指向的元素nums[mid]比较,

二分查找

但是这个代码还有一处问题,在哪呢?

int mid = (left + right) / 2;

这个地方可能会因为left和right数值太大导致内存溢出,所以应该写为 int mid = left + ((right - left) 1);

修改之后代码如下:

时间复杂度:O(logn)

题目:35. 搜索插入位置 ()

难度:简单

描述:

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

请必须使用时间复杂度为 O(log n) 的算法。

题目示例

思路:

二分查找比较简单,但写对还要费点功夫,再做一道基本一样的题巩固一下。

这道题基本一样,插入的位置可能有四种情况:

二叉树插入位置

代码如下:

时间复杂度:O(logn)

题目:34. 在排序数组中查找元素的第一个和最后一个位置 ()

难度:中等

描述:

给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。

如果数组中不存在目标值 target,返回 [-1, -1]。

进阶:

题目示例

思路:

看到时间复杂度 O(log n) ,数组有序,我们知道,二分查找该上场了。

但是这道题有点不一样,它需要寻找边界。

那我们怎么办呢?

这就引入了寻找边界的二分查找。

这道题的思路是什么呢?

我们分别用二分查找来寻找左边界和右边界。

一般的二分查找:

注意,我们这里的返回条件是 nums[mid] == target ,但是寻找边界的时候就不能这样了,因为我们不能确定mid是不是我们的边界。

以寻找左边界为例,条件是 target = nums[mid] 的时候,我们接着往左移动。

寻找右边界也类似。

代码如下:

时间复杂度:O(logn)

题目:27. 移除元素 ()

难度:简单

描述:

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

说明:

为什么返回数值是整数,但输出的答案是数组呢?

请注意,输入数组是以「引用」方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。

你可以想象内部操作如下:

思路

「暴力解法」

暴力解法没什么好说的,和上道题类似,找到要删除的元素,把它后面的元素全部向前移动一位。

暴力解法

这里有两点需要注意:

代码如下:

时间复杂度:O(n²)。

「双指针法」

双指针法,是数组和链表题中非常常用的一种方法。

这道题用双指针法怎么解决呢?

定义两个指针,一个前,一个后。没有找到目标的时候front和after一起移动,找到目标的时候,after停下来,front接着移动,把front指向的值赋给after指向的值。

这样一来,双指针就通过一个循环完成了双循环完成的事情。

双指针法

代码如下:

时间复杂度:O(n)。

题目:27. 移除元素 ()

难度:简单

描述:

给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。

不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。

说明:

为什么返回数值是整数,但输出的答案是数组呢?

请注意,输入数组是以「引用」方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。

你可以想象内部操作如下:

题目示例

思路

趁着上一道题劲儿还没缓过来,赶紧做一道基本一样的巩固一下。

直接上代码:

时间复杂度:O(n)。

题目:283. 移动零 ()

难度:简单

描述:

给定一个数组 nums ,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

「示例:」

「说明」 :

思路

继续沿着上一道题的思路。

移动零

代码如下:

时间复杂度:O(n)。

题目:977. 有序数组的平方 ()

难度:简单

描述:

给你一个按 「非递减顺序」 排序的整数数组 nums ,返回 「每个数字的平方」 组成的新数组,要求也按 「非递减顺序」 排序。

题目示例

思路

「暴力排序法」

这道题一看,最直观的做法是什么呢?

先求数字平方的数组,然后再把新数组排序。

代码也好写:

时间复杂度:遍历时间复杂度O(n),快排时间复杂度O(nlogn),所以时间复杂度O(n+nlogn)。

思路

「双指针法」

我们连写几道双指针了,这道题能不能用双指针实现呢?

我们分析一下,这个数组在取平方之前,是有序的,那么它绝对值最大的数一定是在两端的。

所以我们可以定义两个指针,一个指向最左端,一个指向最右端,比较两者平方的大小,大的平方放入结果数组,并移动指针。

有序数组的平方

代码如下:

时间复杂度:O(n)。

题目:1. 两数之和 ()

难度:简单

描述:给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

题目示例

思路:

「暴力解法」

上来我们先来个最简单的暴力解法,大家应该都知道冒泡排序吧,类似的两层循环。

两层循环

代码写起来也很简单:

时间复杂度:看到这个双循环,就知道时间复杂度O(n²)。

「哈希辅助法」

时间复杂度O(n²)多少有点过了,这道题的重点是两个元素相加之和的判断。

我们可以用一个Hash集合把元素存起来,这样一来遍历一遍就够了,例如目标和9,当前元素2,只需要判断集合里是否有元素7就行了。

时间复杂度:从Hash查询和取值时间复杂度都是O(1),所以整体时间复杂度是O(1)。

题目:15. 三数之和 ()

难度:简单

描述:

给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为0且不重复的三元组。

注意:答案中不可以包含重复的三元组。

题目示例

思路:

「哈希法」

做完两数之和以后,我们首先想到的就是哈希法。

两层循环,取到a,b,再通过 0-(a+b) 来确定c。

但是这里还有一个问题, 答案中不可以包含重复的三元组。

所以,我们还要想办法去掉Hash里的重复元素。

可以加入一个约束,第三个数的索引大于第二个数才存入。

时间复杂度:双循环,O(n²)。

虽然这么也写出来了,但是,说实话,很难写出没有问题的代码。

我们写了这么多双指针,那么有没有可能用双指针的方式呢?

「双指针法」

首先对数组进行排序,然后遍历数组。

然后再在当前节点后面取左右指针,判断左右指针的值是否等于0-nums[i],然后分别左右移动。

怎么去重呢?

满足条件时,看左指针的值是否和前一个位置相等,右指针的值是否和和它后一个位置的值相等。

双指针法

代码如下:

时间复杂度:O(n²)

题目:18. 四数之和 ()

难度:简单

描述:

给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。

注意:答案中不可以包含重复的四元组。

题目示例

思路:

我们延续三数之和的思路,在三数之和外面再套一层循环。

时间复杂度:O(n³)

题目:209. 长度最小的子数组()

难度:中等

描述:

给定一个含有 n 个正整数的数组和一个正整数 target 。

找出该数组中满足其和 target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。

题目示例

思路

这道题是一道经典的滑动窗口问题[4]。

image-20210801164436322

代码如下:

时间复杂度:O(n),虽然循环里套循环了,但是starrt和end各自被移动了n次,所以时间复杂度是O(n)。

题目:219. 存在重复元素 II ()

难度:简单

描述:

给定一个整数数组和一个整数 k,判断数组中是否存在两个不同的索引 i 和 j,使得 nums [i] = nums [j],并且 i 和 j 的差的 绝对值 至多为 k。

题目示例

思路:

上面我们做了一道滑动窗口的题,我们接着再做一道也可以用滑动窗口解决的问题。

这道题的滑动窗口略有区别,上一道题的窗口是活动的,这个是 固定的滑动窗口 ,维护一个长度为k的固定窗口,如果窗口内含有目标值,返回。如果窗口进入新的元素,就需要把头部的元素移除掉,保持窗口的长度。

固定窗口

代码如下:

时间复杂度:O(n)。

题目:1052. 爱生气的书店老板()

难度:中等

描述:

今天,书店老板有一家店打算试营业 customers.length 分钟。每分钟都有一些顾客(customers[i])会进入书店,所有这些顾客都会在那一分钟结束后离开。

在某些时候,书店老板会生气。如果书店老板在第 i 分钟生气,那么 grumpy[i] = 1,否则 grumpy[i] = 0。当书店老板生气时,那一分钟的顾客就会不满意,不生气则他们是满意的。

书店老板知道一个秘密技巧,能抑制自己的情绪,可以让自己连续 X 分钟不生气,但却只能使用一次。

请你返回这一天营业下来,最多有多少客户能够感到满意。

「示例:」

思路:

这道题是一道固定窗口的问题。

整体思路就是把不生气的部分作为固定窗口,固定窗口把customers分成了三部分,最后求三部分的最大和。

固定窗口

时间复杂度:O(n)。

空间复杂度:O(1)。

题目:面试题3. 数组中重复的数字 ()

难度:复杂

描述:

找出数组中重复的数字。

在一个长度为 n 的数组 nums 里的所有数字都在 0 n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。

「示例 1:」

思路:

「哈希法」

这种找重复的数字问题,我们脑子里第一下就想起来,用Hash存储元素,然后进行比对。

代码实现也很简单:

时间复杂度:O(n)。

空间复杂度:O(n)

但今天的主角不是它,而是

「原地置换法」

我们注意到一个条件 所有数字都在 0 n-1 的范围内 ,那就在这方面进行操作,我们可以把元素放到它的值对应的下标的位置。

例如 num[2]=1,那我们就把它放到下标1的位置。

接着遍历,元素发现它应该待的坑已经被它的双胞胎兄弟给占了,它就知道,它是多余的那个。

原地置换

代码如下:

时间复杂度:O(n)。

空间复杂度:O(1)

题目:41. 缺失的第一个正数 ()

难度:复杂

描述:

给你一个未排序的整数数组 nums ,请你找出其中没有出现的最小的正整数。

请你实现时间复杂度为 O(n) 并且只使用常数级别额外空间的解决方案。

题目示例

思路

「辅助数组」

这道题有一个非常巧妙地的办法![1]

可以引入一个辅助数组,从1开始,在对应的位置存入原数组对应的元素。如原数组num[0]=1,那么这个元素就应该存入辅助数组 helper[1]。

然后遍历辅助数组,发现的第一个坑就是缺失的第一个正数。

辅助数组

代码如下:

时间复杂度:O(n)。

空间复杂度:O(n)。

「原地置换法」

我们上面用了原地置换法解决了一个问题,降低了空间复杂度,我们这道题是不是也可以呢?

原地置换没法修改数组长度,我们肯定不能nums[i] 存 i 了,我们左移一下,num[i-1]存i。

原地置换

代码实现如下:

时间复杂度:O(n)。

空间复杂度:O(1)。

题目:54. 螺旋矩阵 ()

难度:中等

描述:

给你一个 m 行 n 列的矩阵 matrix ,请按照 「顺时针螺旋顺序」 ,返回矩阵中的所有元素。

示例 1:

示例2

思路

这道题,思路比较容易想,就是上右下左四个方向顺时针遍历数组。

顺时针遍历数组

但是这道题的细节是魔鬼。

有两种,一种是一圈遍历完成,上下左右的位置移动,遍历是左闭右开[的条件。

我们采用的是第二种,每遍历完一条边,就移动对应的位置,遍历就是左闭右闭的条件。

还有一点细节就是值得注意的是,遍历过程中可能会出现出现 top bottom || left right ,其中一对边界彼此交错了。

这意味着此时所有项都遍历完了,如果没有及时 break ,就会重复遍历。

代码如下:

时间复杂度:O(mn),其中 m 和 n 分别是输入矩阵的行数和列数。

题目:59. 螺旋矩阵 II ()

难度:中等

描述:

给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。

示例

思路

和上面一道题基本一模一样,我们往里面套就行了。

代码如下:

时间复杂度:O(n²)

剑指 Offer 29. 顺时针打印矩阵 也是一道类似的题目。

写了个顺口溜总结一下:


网页名称:java刷题代码 Java代码题
当前URL:http://shouzuofang.com/article/doopiji.html

其他资讯