java - 在同一个循环的迭代之间,局部变量是重用还是重新分配?
问题描述
我一直明白,在循环中定义一个局部变量并不会减慢它的速度,因为它们在同一个循环的迭代之间被重用。
我惊讶地发现,当我将局部变量的定义移到循环之外时,它会显着减少内存(39.4Mb 对 40Mb)。
在同一个循环的迭代之间,局部变量是重用还是重新分配?
我也看到了为循环中的局部变量分配空间
重复零问题(leetcode):给定一个固定长度的整数数组 arr,复制每个出现的零,将剩余元素向右移动。
请注意,超出原始数组长度的元素不会被写入。
对输入数组进行上述修改,不要从函数返回任何内容。
import java.util.Arrays;
/**
* algorithm: the zeroes divide the array into sub-arrays or subsets.
* we move or shift the elements exactly once, to their final resting place R.I.P. ;)
* The last subset will be shifted n0s places, the one before it, n0s -1 places and so on...
* O(n)
* @author likejudo
*
*/
public class DuplicateZeroes {
static void arrayCopy(int[] arr, int begin, int end, int n) {
for (int i = end + 1; i >= begin ; i--) {
int destination = i + n;
if (destination < arr.length) {
arr[destination] = arr[i];
}
}
}
public static void duplicateZeros(int[] arr) {
int n0s = 0; // number of zeroes
int last0At = -1; // last zero at index
int boundary = 0; // rightmost boundary
// find total n0s, last0At
for (int i = 0; i < arr.length; i++) {
if (arr[i] == 0) {
n0s++;
last0At = i;
}
}
// System.out.format("n0s=%d last0At=%d \n", n0s, last0At);
// if no zeroes or all zeroes, we are done
if(n0s == 0 || n0s == arr.length) {
return;
}
boundary = arr.length - n0s;
while (n0s > 0) {
// System.out.format("before arrayCopy(%s, %d, %d, %d) ", Arrays.toString(arr), last0At, boundary, n0s);
// move subset of all elements from last0At till boundary-1, by n0s spaces.
arrayCopy(arr, last0At, boundary, n0s);
// set start of subset to 0
arr[last0At] = 0;
// System.out.format("after arrayCopy : %s assigned arr[last0At=%d]=0\n", Arrays.toString(arr),last0At);
// update boundary
boundary = last0At - 1;
// next subset to the left will have one less zero
n0s--;
last0At--;
// find the next last zer0 At index
while (last0At > 0 && arr[last0At] != 0)
last0At--;
// if no more...
if (last0At <0 || arr[last0At] != 0) {
return;
}
}
}
public static void main(String[] args) {
// input: [1, 0, 2, 3, 0, 4, 5, 0]
// output: [1, 0, 0, 2, 3, 0, 0, 4]
int[] arr = {0,0,0,0,0,0,0};
System.out.println("input: " + Arrays.toString(arr));
duplicateZeros(arr);
System.out.println("output: " + Arrays.toString(arr));
}
}
在方法arrayCopy中,当我将局部变量移到destination
循环外时,
前
static void arrayCopy(int[] arr, int begin, int end, int n) {
for (int i = end + 1; i >= begin ; i--) {
int destination = i + n; // >>>>>>>>>>>>>>>>>>>>>>>
if (destination < arr.length) {
arr[destination] = arr[i];
}
}
}
后
内存使用得到改善!(39.4 Mb 与 40 Mb)
static void arrayCopy(int[] arr, int begin, int end, int n) {
int destination = 0; // >>>>>>>>>>>>>>>>>
for (int i = end + 1; i >= begin ; i--) {
destination = i + n;
if (destination < arr.length) {
arr[destination] = arr[i];
}
}
}
解决方案
关于你的问题
我一直明白,在循环中定义一个局部变量并不会减慢它的速度,因为它们在同一个循环的迭代之间被重用。
在循环内声明局部变量不会减慢速度吗?
是的你是对的。声明本地变量不会增加时间复杂度,或者如果它确实改变了运行时间,那么它太微不足道了,无法考虑。
LeetCode 的运行时和内存测量非常不准确,尤其是运行时。例如,我刚刚重新提交了以下解决方案,它说 39.6 MB,几天前说 43.3 MB 完全相同的解决方案没有字节更改:
- Their test cases are usually limited because it is costly I guess, thus their benchmarking is not valuable.
public final class Solution {
public static final void duplicateZeros(int[] arr) {
int countZero = 0;
for (int index = 0; index < arr.length; index++)
if (arr[index] == 0) {
countZero++;
}
int length = arr.length + countZero;
for (int indexA = arr.length - 1, indexB = length - 1; indexA < indexB; indexA--, indexB--)
if (arr[indexA] != 0) {
if (indexB < arr.length) {
arr[indexB] = arr[indexA];
}
} else {
if (indexB < arr.length) {
arr[indexB] = arr[indexA];
}
indexB--;
if (indexB < arr.length) {
arr[indexB] = arr[indexA];
}
}
}
}
- Overall it'd be best to focus on asymptotically efficient algorithms mostly, because benchmarking has lots of "how-tos" and we'd want to have really good resources (CPU, memory, etc.) with isolated test systems.
References
推荐阅读
- ups - UPS 货件 JSON 文档
- c# - 将 XML 反序列化为 for 循环中的 C# 对象列表太慢
- mysql - 计算来自两个不同表的记录数并将它们分组
- javascript - 如何在按钮 onclick 上将动态创建的元素 id 传递给 javascript 函数。
- apache-kafka - ibm-eventstreams 是否支持 Kafka ACL?
- nativescript - 如何在 NativeScript 中调用可变参数函数?
- html - 仅 CSS 导航 - 单选框显示/隐藏页面
- html - 如何为部分添加背景颜色
- permissions - GitLab 成员的默认开发人员权限
- node.js - 按数组mongodb查询的长度排序