RESTful API 是每个程序员都应该了解并掌握的基本知识,我们在开发过程中设计 API 的时候也应该至少要满足 RESTful API 的最基本的要求(比如接口中尽量使用名词,使用 POST 请求创建资源,DELETE 请求删除资源等等,示例:GET /notes/id:获取某个指定 id 的笔记的信息)。
如果你看 RESTful API 相关的文章的话一般都比较晦涩难懂,包括我下面的文章也会提到一些概念性的东西。但是,实际上我们平时开发用到的 RESTful API 的知识非常简单也很容易概括!举个例子,如果我给你下面两个 url 你是不是立马能知道它们是干什么的!这就是 RESTful API 的强大之处!
资源(Resource) :我们可以把真实的对象数据称为资源。一个资源既可以是一个集合,也可以是单个个体。比如我们的班级 classes 是代表一个集合形式的资源,而特定的 class 代表单个个体资源。每一种资源都有特定的 URI(统一资源定位符)与之对应,如果我们需要获取这个资源,访问这个 URI 就可以了,比如获取特定的班级:/class/12。另外,资源也可以包含子资源,比如 /classes/classId/teachers:列出某个指定班级的所有老师的信息
Talk is cheap!来举个实际的例子来说明一下吧!现在有这样一个 API 提供班级(class)的信息,还包括班级中的学生和教师的信息,则它的路径应该设计成下面这样。
接口尽量使用名词,禁止使用动词。 下面是一些例子:
1 2 3 4 5 6 7 8 9
GET /classes:列出所有班级 POST /classes:新建一个班级 GET /classes/classId:获取某个指定班级的信息 PUT /classes/classId:更新某个指定班级的信息(一般倾向整体更新) PATCH /classes/classId:更新某个指定班级的信息(一般倾向部分更新) DELETE /classes/classId:删除某个班级 GET /classes/classId/teachers:列出某个指定班级的所有老师的信息 GET /classes/classId/students:列出某个指定班级的所有学生的信息 DELETE classes/classId/teachers/ID:删除某个指定班级下的指定的老师的信息
上面代码表示,文档中有一个 link 属性,用户读取这个属性就知道下一步该调用什么 API 了。rel 表示这个 API 与当前网址的关系(collection 关系,并给出该 collection 的网址),href 表示 API 的路径,title 表示 API 的标题,type 表示返回类型 Hypermedia API 的设计被称为HATEOAS。
在 Spring 中有一个叫做 HATEOAS 的 API 库,通过它我们可以更轻松的创建除符合 HATEOAS 设计的 API。
publicintmaxProfit(int[] prices){ int len = prices.length; if (len < 2) { return0; }
// cash:持有现金 // hold:持有股票 // 状态转移:cash → hold → cash → hold → cash → hold → cash
int cash = 0; int hold = -prices[0];
int preCash = cash; int preHold = hold; for (int i = 1; i < len; i++) { cash = Math.max(preCash, preHold + prices[i]); hold = Math.max(preHold, preCash - prices[i]);
publicclassSolution{ publicbooleanFind(int target, int [][] array){ if(array==null) returnfalse; int n = array.length; int m = array[0].length; if(n==0||m==0) returnfalse; int i = 0; int j = m-1; //查看最右上角的位置 while(i<n&&i>=0 && j<m && j>=0){ if(target==array[i][j]) returntrue; elseif(target>array[i][j])//不要写成 if 结构 i++; elseif(target<array[i][j]) j--; } returnfalse; } }
classSolution{ publicintsingleNumber(int[] nums){ int y = 0, x = 0; for (int z : nums) { int _y = y; y = ~x & (y ^ z); x = x&(~_y)&(~z)|(~x)&(_y)&(z); } return y; } }
publicclassSolution{ // you need to treat n as an unsigned value publicinthammingWeight(int n){ int count = 0; while (n != 0) { count++; n = n & (n - 1); } return count; } }
201.数字范围按位与
题目描述
给定范围 [m, n],其中 0 <= m <= n <= 2147483647,返回此范围内所有数字的按位与(包含 m, n 两端点)。
classSolution{ publicintrangeBitwiseAnd(int m, int n){ int shift = 0; // find the common 1-bits while (m < n) { m >>= 1; n >>= 1; ++shift; } return m << shift; } }
利用n&(n-1)
1 2 3 4 5 6 7 8 9
classSolution{ publicintrangeBitwiseAnd(int m, int n){ while (m < n) { // turn off rightmost 1-bit n = n & (n - 1); } return n; } }
for (int i = 1; i < nums.length; i++) { // // If the current element is a duplicate, increment the count. // if (nums[i] == nums[i - 1]) { count++; } else { // // Reset the count since we encountered a different element // than the previous one. // count = 1; } // // For a count <= 2, we copy the element over thus // overwriting the element at index "j" in the array // if (count <= 2) { nums[j++] = nums[i]; } } return j; } }
publicinttrap6(int[] height){ int sum = 0; Stack<Integer> stack = new Stack<>(); int current = 0; while (current < height.length) { //如果栈不空并且当前指向的高度大于栈顶高度就一直循环 while (!stack.empty() && height[current] > height[stack.peek()]) { int h = height[stack.peek()]; //取出要出栈的元素 stack.pop(); //出栈 if (stack.empty()) { // 栈空就出去 break; } int distance = current - stack.peek() - 1; //两堵墙之前的距离。 int min = Math.min(height[stack.peek()], height[current]); sum = sum + distance * (min - h); } stack.push(current); //当前指向的墙入栈 current++; //指针后移 } return sum; }
publicintlargestRectangleArea(int[] heights){ int len = heights.length; if (len == 0) { return0; } if (len == 1) { return heights[0]; }
int res = 0; Deque<Integer> stack = new ArrayDeque<>(len); for (int i = 0; i < len; i++) { // 这个 while 很关键,因为有可能不止一个柱形的最大宽度可以被计算出来 while (!stack.isEmpty() && heights[i] < heights[stack.peekLast()]) { int curHeight = heights[stack.pollLast()]; while (!stack.isEmpty() && heights[stack.peekLast()] == curHeight) { stack.pollLast(); }
int curWidth; if (stack.isEmpty()) { curWidth = i; } else { curWidth = i - stack.peekLast() - 1; }
// System.out.println("curIndex = " + curIndex + " " + curHeight * curWidth); res = Math.max(res, curHeight * curWidth); } stack.addLast(i); } //未加哨兵,所以最后怕栈里面不干净,还需要计算再计算 while (!stack.isEmpty()) { int curHeight = heights[stack.pollLast()]; while (!stack.isEmpty() && heights[stack.peekLast()] == curHeight) { stack.pollLast(); } int curWidth; if (stack.isEmpty()) { curWidth = len; } else { curWidth = len - stack.peekLast() - 1; } res = Math.max(res, curHeight * curWidth); } return res; } }